blob: b96380eadd6baf6ca61d718e4346e60d45477126 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * edit.c: functions for Insert mode
12 */
13
14#include "vim.h"
15
16#ifdef FEAT_INS_EXPAND
17/*
18 * definitions used for CTRL-X submode
19 */
20#define CTRL_X_WANT_IDENT 0x100
21
22#define CTRL_X_NOT_DEFINED_YET 1
23#define CTRL_X_SCROLL 2
24#define CTRL_X_WHOLE_LINE 3
25#define CTRL_X_FILES 4
26#define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
27#define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
28#define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
29#define CTRL_X_FINISHED 8
30#define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
31#define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
32#define CTRL_X_CMDLINE 11
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +000033#define CTRL_X_FUNCTION 12
Bram Moolenaarf75a9632005-09-13 21:20:47 +000034#define CTRL_X_OMNI 13
Bram Moolenaar488c6512005-08-11 20:09:58 +000035#define CTRL_X_SPELL 14
36#define CTRL_X_LOCAL_MSG 15 /* only used in "ctrl_x_msgs" */
Bram Moolenaar071d4272004-06-13 20:20:40 +000037
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
39
40static char *ctrl_x_msgs[] =
41{
42 N_(" Keyword completion (^N^P)"), /* ctrl_x_mode == 0, ^P/^N compl. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +000043 N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
Bram Moolenaar4be06f92005-07-29 22:36:03 +000044 NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +000045 N_(" Whole line completion (^L^N^P)"),
46 N_(" File name completion (^F^N^P)"),
47 N_(" Tag completion (^]^N^P)"),
48 N_(" Path pattern completion (^N^P)"),
49 N_(" Definition completion (^D^N^P)"),
50 NULL,
51 N_(" Dictionary completion (^K^N^P)"),
52 N_(" Thesaurus completion (^T^N^P)"),
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +000053 N_(" Command-line completion (^V^N^P)"),
54 N_(" User defined completion (^U^N^P)"),
Bram Moolenaarf75a9632005-09-13 21:20:47 +000055 N_(" Omni completion (^O^N^P)"),
Bram Moolenaar910f66f2006-04-05 20:41:53 +000056 N_(" Spelling suggestion (s^N^P)"),
Bram Moolenaar4be06f92005-07-29 22:36:03 +000057 N_(" Keyword Local completion (^N^P)"),
Bram Moolenaar071d4272004-06-13 20:20:40 +000058};
59
60static char_u e_hitend[] = N_("Hit end of paragraph");
61
62/*
63 * Structure used to store one match for insert completion.
64 */
Bram Moolenaard1f56e62006-02-22 21:25:37 +000065typedef struct compl_S compl_T;
66struct compl_S
Bram Moolenaar071d4272004-06-13 20:20:40 +000067{
Bram Moolenaar572cb562005-08-05 21:35:02 +000068 compl_T *cp_next;
69 compl_T *cp_prev;
70 char_u *cp_str; /* matched text */
Bram Moolenaard1f56e62006-02-22 21:25:37 +000071 char cp_icase; /* TRUE or FALSE: ignore case */
Bram Moolenaar39f05632006-03-19 22:15:26 +000072 char_u *(cp_text[CPT_COUNT]); /* text for the menu */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000073 char_u *cp_fname; /* file containing the match, allocated when
74 * cp_flags has FREE_FNAME */
Bram Moolenaar572cb562005-08-05 21:35:02 +000075 int cp_flags; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
76 int cp_number; /* sequence number */
Bram Moolenaar071d4272004-06-13 20:20:40 +000077};
78
Bram Moolenaar572cb562005-08-05 21:35:02 +000079#define ORIGINAL_TEXT (1) /* the original text when the expansion begun */
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#define FREE_FNAME (2)
81
82/*
83 * All the current matches are stored in a list.
Bram Moolenaar4be06f92005-07-29 22:36:03 +000084 * "compl_first_match" points to the start of the list.
85 * "compl_curr_match" points to the currently selected entry.
86 * "compl_shown_match" is different from compl_curr_match during
87 * ins_compl_get_exp().
Bram Moolenaar071d4272004-06-13 20:20:40 +000088 */
Bram Moolenaar572cb562005-08-05 21:35:02 +000089static compl_T *compl_first_match = NULL;
90static compl_T *compl_curr_match = NULL;
91static compl_T *compl_shown_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
Bram Moolenaar779b74b2006-04-10 14:55:34 +000093/* After using a cursor key <Enter> selects a match in the popup menu,
94 * otherwise it inserts a line break. */
95static int compl_enter_selects = FALSE;
96
Bram Moolenaara6557602006-02-04 22:43:20 +000097/* When "compl_leader" is not NULL only matches that start with this string
98 * are used. */
99static char_u *compl_leader = NULL;
100
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000101static int compl_get_longest = FALSE; /* put longest common string
102 in compl_leader */
103
Bram Moolenaara6557602006-02-04 22:43:20 +0000104static int compl_used_match; /* Selected one of the matches. When
105 FALSE the match was edited or using
106 the longest common string. */
107
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000108/* When the first completion is done "compl_started" is set. When it's
109 * FALSE the word to be completed must be located. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000110static int compl_started = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000111
Bram Moolenaar572cb562005-08-05 21:35:02 +0000112static int compl_matches = 0;
113static char_u *compl_pattern = NULL;
114static int compl_direction = FORWARD;
115static int compl_shows_dir = FORWARD;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000116static int compl_pending = 0; /* > 1 for postponed CTRL-N */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000117static pos_T compl_startpos;
118static colnr_T compl_col = 0; /* column where the text starts
119 * that is being completed */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000120static char_u *compl_orig_text = NULL; /* text as it was before
121 * completion started */
122static int compl_cont_mode = 0;
123static expand_T compl_xp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000125static void ins_ctrl_x __ARGS((void));
126static int has_compl_option __ARGS((int dict_opt));
Bram Moolenaar4a85b412006-04-23 22:40:29 +0000127static int ins_compl_add __ARGS((char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int dup));
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000128static int ins_compl_equal __ARGS((compl_T *match, char_u *str, int len));
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000129static void ins_compl_longest_match __ARGS((compl_T *match));
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000130static void ins_compl_add_matches __ARGS((int num_matches, char_u **matches, int icase));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131static int ins_compl_make_cyclic __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000132static void ins_compl_upd_pum __ARGS((void));
133static void ins_compl_del_pum __ARGS((void));
Bram Moolenaar280f1262006-01-30 00:14:18 +0000134static int pum_wanted __ARGS((void));
Bram Moolenaar65c923a2006-03-03 22:56:30 +0000135static int pum_enough_matches __ARGS((void));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000136static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int flags, int thesaurus));
Bram Moolenaar0b238792006-03-02 22:49:12 +0000137static void ins_compl_files __ARGS((int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000138static char_u *find_line_end __ARGS((char_u *ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139static void ins_compl_free __ARGS((void));
140static void ins_compl_clear __ARGS((void));
Bram Moolenaara6557602006-02-04 22:43:20 +0000141static int ins_compl_bs __ARGS((void));
142static void ins_compl_addleader __ARGS((int c));
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000143static void ins_compl_set_original_text __ARGS((char_u *str));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000144static void ins_compl_addfrommatch __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000145static int ins_compl_prep __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));
Bram Moolenaara94bc432006-03-10 21:42:59 +0000147#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
148static void ins_compl_add_list __ARGS((list_T *list));
149#endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000150static int ins_compl_get_exp __ARGS((pos_T *ini));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151static void ins_compl_delete __ARGS((void));
152static void ins_compl_insert __ARGS((void));
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000153static int ins_compl_next __ARGS((int allow_get_expansion, int count, int insert_match));
Bram Moolenaare3226be2005-12-18 22:10:00 +0000154static int ins_compl_key2dir __ARGS((int c));
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000155static int ins_compl_pum_key __ARGS((int c));
Bram Moolenaare3226be2005-12-18 22:10:00 +0000156static int ins_compl_key2count __ARGS((int c));
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000157static int ins_compl_use_match __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158static int ins_complete __ARGS((int c));
159static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
160#endif /* FEAT_INS_EXPAND */
161
162#define BACKSPACE_CHAR 1
163#define BACKSPACE_WORD 2
164#define BACKSPACE_WORD_NOT_SPACE 3
165#define BACKSPACE_LINE 4
166
Bram Moolenaar754b5602006-02-09 23:53:20 +0000167static void ins_redraw __ARGS((int ready));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168static void ins_ctrl_v __ARGS((void));
169static void undisplay_dollar __ARGS((void));
170static void insert_special __ARGS((int, int, int));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000171static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172static void check_auto_format __ARGS((int));
173static void redo_literal __ARGS((int c));
174static void start_arrow __ARGS((pos_T *end_insert_pos));
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000175#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +0000176static void check_spell_redraw __ARGS((void));
Bram Moolenaar8aff23a2005-08-19 20:40:30 +0000177static void spell_back_to_badword __ARGS((void));
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +0000178static int spell_bad_len = 0; /* length of located bad word */
Bram Moolenaar217ad922005-03-20 22:37:15 +0000179#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180static void stop_insert __ARGS((pos_T *end_insert_pos, int esc));
181static int echeck_abbr __ARGS((int));
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000182#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183static void replace_push_off __ARGS((int c));
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000184#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185static int replace_pop __ARGS((void));
186static void replace_join __ARGS((int off));
187static void replace_pop_ins __ARGS((void));
188#ifdef FEAT_MBYTE
189static void mb_replace_pop_ins __ARGS((int cc));
190#endif
191static void replace_flush __ARGS((void));
192static void replace_do_bs __ARGS((void));
193#ifdef FEAT_CINDENT
194static int cindent_on __ARGS((void));
195#endif
196static void ins_reg __ARGS((void));
197static void ins_ctrl_g __ARGS((void));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000198static void ins_ctrl_hat __ARGS((void));
Bram Moolenaar488c6512005-08-11 20:09:58 +0000199static int ins_esc __ARGS((long *count, int cmdchar, int nomove));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200#ifdef FEAT_RIGHTLEFT
201static void ins_ctrl_ __ARGS((void));
202#endif
203#ifdef FEAT_VISUAL
204static int ins_start_select __ARGS((int c));
205#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000206static void ins_insert __ARGS((int replaceState));
207static void ins_ctrl_o __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208static void ins_shift __ARGS((int c, int lastc));
209static void ins_del __ARGS((void));
210static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
211#ifdef FEAT_MOUSE
212static void ins_mouse __ARGS((int c));
213static void ins_mousescroll __ARGS((int up));
214#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +0000215#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
216static void ins_tabline __ARGS((int c));
217#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218static void ins_left __ARGS((void));
219static void ins_home __ARGS((int c));
220static void ins_end __ARGS((int c));
221static void ins_s_left __ARGS((void));
222static void ins_right __ARGS((void));
223static void ins_s_right __ARGS((void));
224static void ins_up __ARGS((int startcol));
225static void ins_pageup __ARGS((void));
226static void ins_down __ARGS((int startcol));
227static void ins_pagedown __ARGS((void));
228#ifdef FEAT_DND
229static void ins_drop __ARGS((void));
230#endif
231static int ins_tab __ARGS((void));
232static int ins_eol __ARGS((int c));
233#ifdef FEAT_DIGRAPHS
234static int ins_digraph __ARGS((void));
235#endif
236static int ins_copychar __ARGS((linenr_T lnum));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000237static int ins_ctrl_ey __ARGS((int tc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238#ifdef FEAT_SMARTINDENT
239static void ins_try_si __ARGS((int c));
240#endif
241static colnr_T get_nolist_virtcol __ARGS((void));
242
243static colnr_T Insstart_textlen; /* length of line when insert started */
244static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
245
246static char_u *last_insert = NULL; /* the text of the previous insert,
247 K_SPECIAL and CSI are escaped */
248static int last_insert_skip; /* nr of chars in front of previous insert */
249static int new_insert_skip; /* nr of chars in front of current insert */
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000250static int did_restart_edit; /* "restart_edit" when calling edit() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251
252#ifdef FEAT_CINDENT
253static int can_cindent; /* may do cindenting on this line */
254#endif
255
256static int old_indent = 0; /* for ^^D command in insert mode */
257
258#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +0000259static int revins_on; /* reverse insert mode on */
260static int revins_chars; /* how much to skip after edit */
261static int revins_legal; /* was the last char 'legal'? */
262static int revins_scol; /* start column of revins session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263#endif
264
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265static int ins_need_undo; /* call u_save() before inserting a
266 char. Set when edit() is called.
267 after that arrow_used is used. */
268
269static int did_add_space = FALSE; /* auto_format() added an extra space
270 under the cursor */
271
272/*
273 * edit(): Start inserting text.
274 *
275 * "cmdchar" can be:
276 * 'i' normal insert command
277 * 'a' normal append command
278 * 'R' replace command
279 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
280 * but still only one <CR> is inserted. The <Esc> is not used for redo.
281 * 'g' "gI" command.
282 * 'V' "gR" command for Virtual Replace mode.
283 * 'v' "gr" command for single character Virtual Replace mode.
284 *
285 * This function is not called recursively. For CTRL-O commands, it returns
286 * and lets the caller handle the Normal-mode command.
287 *
288 * Return TRUE if a CTRL-O command caused the return (insert mode pending).
289 */
290 int
291edit(cmdchar, startln, count)
292 int cmdchar;
293 int startln; /* if set, insert at start of line */
294 long count;
295{
296 int c = 0;
297 char_u *ptr;
298 int lastc;
299 colnr_T mincol;
300 static linenr_T o_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 int i;
302 int did_backspace = TRUE; /* previous char was backspace */
303#ifdef FEAT_CINDENT
304 int line_is_white = FALSE; /* line is empty before insert */
305#endif
306 linenr_T old_topline = 0; /* topline before insertion */
307#ifdef FEAT_DIFF
308 int old_topfill = -1;
309#endif
310 int inserted_space = FALSE; /* just inserted a space */
311 int replaceState = REPLACE;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000312 int nomove = FALSE; /* don't move cursor on return */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000314 /* Remember whether editing was restarted after CTRL-O. */
315 did_restart_edit = restart_edit;
316
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317 /* sleep before redrawing, needed for "CTRL-O :" that results in an
318 * error message */
319 check_for_delay(TRUE);
320
321#ifdef HAVE_SANDBOX
322 /* Don't allow inserting in the sandbox. */
323 if (sandbox != 0)
324 {
325 EMSG(_(e_sandbox));
326 return FALSE;
327 }
328#endif
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000329 /* Don't allow changes in the buffer while editing the cmdline. The
330 * caller of getcmdline() may get confused. */
Bram Moolenaarb71eaae2006-01-20 23:10:18 +0000331 if (textlock != 0)
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000332 {
333 EMSG(_(e_secure));
334 return FALSE;
335 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336
337#ifdef FEAT_INS_EXPAND
338 ins_compl_clear(); /* clear stuff for CTRL-X mode */
339#endif
340
Bram Moolenaar843ee412004-06-30 16:16:41 +0000341#ifdef FEAT_AUTOCMD
342 /*
343 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
344 */
345 if (cmdchar != 'r' && cmdchar != 'v')
346 {
Bram Moolenaar1e015462005-09-25 22:16:38 +0000347# ifdef FEAT_EVAL
Bram Moolenaar843ee412004-06-30 16:16:41 +0000348 if (cmdchar == 'R')
349 ptr = (char_u *)"r";
350 else if (cmdchar == 'V')
351 ptr = (char_u *)"v";
352 else
353 ptr = (char_u *)"i";
354 set_vim_var_string(VV_INSERTMODE, ptr, 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +0000355# endif
Bram Moolenaar843ee412004-06-30 16:16:41 +0000356 apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);
357 }
358#endif
359
Bram Moolenaar071d4272004-06-13 20:20:40 +0000360#ifdef FEAT_MOUSE
361 /*
362 * When doing a paste with the middle mouse button, Insstart is set to
363 * where the paste started.
364 */
365 if (where_paste_started.lnum != 0)
366 Insstart = where_paste_started;
367 else
368#endif
369 {
370 Insstart = curwin->w_cursor;
371 if (startln)
372 Insstart.col = 0;
373 }
374 Insstart_textlen = linetabsize(ml_get_curline());
375 Insstart_blank_vcol = MAXCOL;
376 if (!did_ai)
377 ai_col = 0;
378
379 if (cmdchar != NUL && restart_edit == 0)
380 {
381 ResetRedobuff();
382 AppendNumberToRedobuff(count);
383#ifdef FEAT_VREPLACE
384 if (cmdchar == 'V' || cmdchar == 'v')
385 {
386 /* "gR" or "gr" command */
387 AppendCharToRedobuff('g');
388 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
389 }
390 else
391#endif
392 {
393 AppendCharToRedobuff(cmdchar);
394 if (cmdchar == 'g') /* "gI" command */
395 AppendCharToRedobuff('I');
396 else if (cmdchar == 'r') /* "r<CR>" command */
397 count = 1; /* insert only one <CR> */
398 }
399 }
400
401 if (cmdchar == 'R')
402 {
403#ifdef FEAT_FKMAP
404 if (p_fkmap && p_ri)
405 {
406 beep_flush();
407 EMSG(farsi_text_3); /* encoded in Farsi */
408 State = INSERT;
409 }
410 else
411#endif
412 State = REPLACE;
413 }
414#ifdef FEAT_VREPLACE
415 else if (cmdchar == 'V' || cmdchar == 'v')
416 {
417 State = VREPLACE;
418 replaceState = VREPLACE;
419 orig_line_count = curbuf->b_ml.ml_line_count;
420 vr_lines_changed = 1;
421 }
422#endif
423 else
424 State = INSERT;
425
426 stop_insert_mode = FALSE;
427
428 /*
429 * Need to recompute the cursor position, it might move when the cursor is
430 * on a TAB or special character.
431 */
432 curs_columns(TRUE);
433
434 /*
435 * Enable langmap or IME, indicated by 'iminsert'.
436 * Note that IME may enabled/disabled without us noticing here, thus the
437 * 'iminsert' value may not reflect what is actually used. It is updated
438 * when hitting <Esc>.
439 */
440 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
441 State |= LANGMAP;
442#ifdef USE_IM_CONTROL
443 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
444#endif
445
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446#ifdef FEAT_MOUSE
447 setmouse();
448#endif
449#ifdef FEAT_CMDL_INFO
450 clear_showcmd();
451#endif
452#ifdef FEAT_RIGHTLEFT
453 /* there is no reverse replace mode */
454 revins_on = (State == INSERT && p_ri);
455 if (revins_on)
456 undisplay_dollar();
457 revins_chars = 0;
458 revins_legal = 0;
459 revins_scol = -1;
460#endif
461
462 /*
463 * Handle restarting Insert mode.
464 * Don't do this for "CTRL-O ." (repeat an insert): we get here with
465 * restart_edit non-zero, and something in the stuff buffer.
466 */
467 if (restart_edit != 0 && stuff_empty())
468 {
469#ifdef FEAT_MOUSE
470 /*
471 * After a paste we consider text typed to be part of the insert for
472 * the pasted text. You can backspace over the pasted text too.
473 */
474 if (where_paste_started.lnum)
475 arrow_used = FALSE;
476 else
477#endif
478 arrow_used = TRUE;
479 restart_edit = 0;
480
481 /*
482 * If the cursor was after the end-of-line before the CTRL-O and it is
483 * now at the end-of-line, put it after the end-of-line (this is not
484 * correct in very rare cases).
485 * Also do this if curswant is greater than the current virtual
486 * column. Eg after "^O$" or "^O80|".
487 */
488 validate_virtcol();
489 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000490 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 || curwin->w_curswant > curwin->w_virtcol)
492 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
493 {
494 if (ptr[1] == NUL)
495 ++curwin->w_cursor.col;
496#ifdef FEAT_MBYTE
497 else if (has_mbyte)
498 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000499 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 if (ptr[i] == NUL)
501 curwin->w_cursor.col += i;
502 }
503#endif
504 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000505 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 }
507 else
508 arrow_used = FALSE;
509
510 /* we are in insert mode now, don't need to start it anymore */
511 need_start_insertmode = FALSE;
512
513 /* Need to save the line for undo before inserting the first char. */
514 ins_need_undo = TRUE;
515
516#ifdef FEAT_MOUSE
517 where_paste_started.lnum = 0;
518#endif
519#ifdef FEAT_CINDENT
520 can_cindent = TRUE;
521#endif
522#ifdef FEAT_FOLDING
523 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
524 * restarting. */
525 if (!p_im && did_restart_edit == 0)
526 foldOpenCursor();
527#endif
528
529 /*
530 * If 'showmode' is set, show the current (insert/replace/..) mode.
531 * A warning message for changing a readonly file is given here, before
532 * actually changing anything. It's put after the mode, if any.
533 */
534 i = 0;
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000535 if (p_smd && msg_silent == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 i = showmode();
537
538 if (!p_im && did_restart_edit == 0)
539 change_warning(i + 1);
540
541#ifdef CURSOR_SHAPE
542 ui_cursor_shape(); /* may show different cursor shape */
543#endif
544#ifdef FEAT_DIGRAPHS
545 do_digraph(-1); /* clear digraphs */
546#endif
547
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000548 /*
549 * Get the current length of the redo buffer, those characters have to be
550 * skipped if we want to get to the inserted characters.
551 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 ptr = get_inserted();
553 if (ptr == NULL)
554 new_insert_skip = 0;
555 else
556 {
557 new_insert_skip = (int)STRLEN(ptr);
558 vim_free(ptr);
559 }
560
561 old_indent = 0;
562
563 /*
564 * Main loop in Insert mode: repeat until Insert mode is left.
565 */
566 for (;;)
567 {
568#ifdef FEAT_RIGHTLEFT
569 if (!revins_legal)
570 revins_scol = -1; /* reset on illegal motions */
571 else
572 revins_legal = 0;
573#endif
574 if (arrow_used) /* don't repeat insert when arrow key used */
575 count = 0;
576
577 if (stop_insert_mode)
578 {
579 /* ":stopinsert" used or 'insertmode' reset */
580 count = 0;
581 goto doESCkey;
582 }
583
584 /* set curwin->w_curswant for next K_DOWN or K_UP */
585 if (!arrow_used)
586 curwin->w_set_curswant = TRUE;
587
588 /* If there is no typeahead may check for timestamps (e.g., for when a
589 * menu invoked a shell command). */
590 if (stuff_empty())
591 {
592 did_check_timestamps = FALSE;
593 if (need_check_timestamps)
594 check_timestamps(FALSE);
595 }
596
597 /*
598 * When emsg() was called msg_scroll will have been set.
599 */
600 msg_scroll = FALSE;
601
602#ifdef FEAT_GUI
603 /* When 'mousefocus' is set a mouse movement may have taken us to
604 * another window. "need_mouse_correct" may then be set because of an
605 * autocommand. */
606 if (need_mouse_correct)
607 gui_mouse_correct();
608#endif
609
610#ifdef FEAT_FOLDING
611 /* Open fold at the cursor line, according to 'foldopen'. */
612 if (fdo_flags & FDO_INSERT)
613 foldOpenCursor();
614 /* Close folds where the cursor isn't, according to 'foldclose' */
615 if (!char_avail())
616 foldCheckClose();
617#endif
618
619 /*
620 * If we inserted a character at the last position of the last line in
621 * the window, scroll the window one line up. This avoids an extra
622 * redraw.
623 * This is detected when the cursor column is smaller after inserting
624 * something.
625 * Don't do this when the topline changed already, it has
626 * already been adjusted (by insertchar() calling open_line())).
627 */
628 if (curbuf->b_mod_set
629 && curwin->w_p_wrap
630 && !did_backspace
631 && curwin->w_topline == old_topline
632#ifdef FEAT_DIFF
633 && curwin->w_topfill == old_topfill
634#endif
635 )
636 {
637 mincol = curwin->w_wcol;
638 validate_cursor_col();
639
640 if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts
641 && curwin->w_wrow == W_WINROW(curwin)
642 + curwin->w_height - 1 - p_so
643 && (curwin->w_cursor.lnum != curwin->w_topline
644#ifdef FEAT_DIFF
645 || curwin->w_topfill > 0
646#endif
647 ))
648 {
649#ifdef FEAT_DIFF
650 if (curwin->w_topfill > 0)
651 --curwin->w_topfill;
652 else
653#endif
654#ifdef FEAT_FOLDING
655 if (hasFolding(curwin->w_topline, NULL, &old_topline))
656 set_topline(curwin, old_topline + 1);
657 else
658#endif
659 set_topline(curwin, curwin->w_topline + 1);
660 }
661 }
662
663 /* May need to adjust w_topline to show the cursor. */
664 update_topline();
665
666 did_backspace = FALSE;
667
668 validate_cursor(); /* may set must_redraw */
669
670 /*
671 * Redraw the display when no characters are waiting.
672 * Also shows mode, ruler and positions cursor.
673 */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000674 ins_redraw(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675
676#ifdef FEAT_SCROLLBIND
677 if (curwin->w_p_scb)
678 do_check_scrollbind(TRUE);
679#endif
680
681 update_curswant();
682 old_topline = curwin->w_topline;
683#ifdef FEAT_DIFF
684 old_topfill = curwin->w_topfill;
685#endif
686
687#ifdef USE_ON_FLY_SCROLL
688 dont_scroll = FALSE; /* allow scrolling here */
689#endif
690
691 /*
692 * Get a character for Insert mode.
693 */
694 lastc = c; /* remember previous char for CTRL-D */
695 c = safe_vgetc();
696
697#ifdef FEAT_RIGHTLEFT
698 if (p_hkmap && KeyTyped)
699 c = hkmap(c); /* Hebrew mode mapping */
700#endif
701#ifdef FEAT_FKMAP
702 if (p_fkmap && KeyTyped)
703 c = fkmap(c); /* Farsi mode mapping */
704#endif
705
706#ifdef FEAT_INS_EXPAND
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000707 /*
708 * Special handling of keys while the popup menu is visible or wanted
709 * and the cursor is still in the completed word.
710 */
711 if (compl_started && pum_wanted() && curwin->w_cursor.col >= compl_col)
Bram Moolenaara6557602006-02-04 22:43:20 +0000712 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000713 /* BS: Delete one character from "compl_leader". */
714 if ((c == K_BS || c == Ctrl_H)
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000715 && curwin->w_cursor.col > compl_col
716 && (c = ins_compl_bs()) == NUL)
Bram Moolenaara6557602006-02-04 22:43:20 +0000717 continue;
718
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000719 /* When no match was selected or it was edited. */
720 if (!compl_used_match)
Bram Moolenaara6557602006-02-04 22:43:20 +0000721 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000722 /* CTRL-L: Add one character from the current match to
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000723 * "compl_leader". Except when at the original match and
724 * there is nothing to add, CTRL-L works like CTRL-P then. */
725 if (c == Ctrl_L
726 && (ctrl_x_mode != CTRL_X_WHOLE_LINE
727 || STRLEN(compl_shown_match->cp_str)
728 > curwin->w_cursor.col - compl_col))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000729 {
730 ins_compl_addfrommatch();
731 continue;
732 }
733
Bram Moolenaardf1bdc92006-02-23 21:32:16 +0000734 /* A printable, non-white character: Add to "compl_leader". */
735 if (vim_isprintc(c) && !vim_iswhite(c))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000736 {
737 ins_compl_addleader(c);
738 continue;
739 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000740
Bram Moolenaar779b74b2006-04-10 14:55:34 +0000741 /* Pressing CTRL-Y selects the current match. Shen
742 * compl_enter_selects is set the Enter key does the same. */
743 if (c == Ctrl_Y || (compl_enter_selects
744 && (c == CAR || c == K_KENTER || c == NL)))
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000745 {
746 ins_compl_delete();
747 ins_compl_insert();
748 }
Bram Moolenaara6557602006-02-04 22:43:20 +0000749 }
750 }
751
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
753 * it does fix up the text when finishing completion. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000754 compl_get_longest = FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +0000755 if (c != K_IGNORE && ins_compl_prep(c))
756 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757#endif
758
Bram Moolenaar488c6512005-08-11 20:09:58 +0000759 /* CTRL-\ CTRL-N goes to Normal mode,
760 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
761 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 if (c == Ctrl_BSL)
763 {
764 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000765 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 ++no_mapping;
767 ++allow_keys;
768 c = safe_vgetc();
769 --no_mapping;
770 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000771 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000773 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 vungetc(c);
775 c = Ctrl_BSL;
776 }
777 else if (c == Ctrl_G && p_im)
778 continue;
779 else
780 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000781 if (c == Ctrl_O)
782 {
783 ins_ctrl_o();
784 ins_at_eol = FALSE; /* cursor keeps its column */
785 nomove = TRUE;
786 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 count = 0;
788 goto doESCkey;
789 }
790 }
791
792#ifdef FEAT_DIGRAPHS
793 c = do_digraph(c);
794#endif
795
796#ifdef FEAT_INS_EXPAND
797 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
798 goto docomplete;
799#endif
800 if (c == Ctrl_V || c == Ctrl_Q)
801 {
802 ins_ctrl_v();
803 c = Ctrl_V; /* pretend CTRL-V is last typed character */
804 continue;
805 }
806
807#ifdef FEAT_CINDENT
808 if (cindent_on()
809# ifdef FEAT_INS_EXPAND
810 && ctrl_x_mode == 0
811# endif
812 )
813 {
814 /* A key name preceded by a bang means this key is not to be
815 * inserted. Skip ahead to the re-indenting below.
816 * A key name preceded by a star means that indenting has to be
817 * done before inserting the key. */
818 line_is_white = inindent(0);
819 if (in_cinkeys(c, '!', line_is_white))
820 goto force_cindent;
821 if (can_cindent && in_cinkeys(c, '*', line_is_white)
822 && stop_arrow() == OK)
823 do_c_expr_indent();
824 }
825#endif
826
827#ifdef FEAT_RIGHTLEFT
828 if (curwin->w_p_rl)
829 switch (c)
830 {
831 case K_LEFT: c = K_RIGHT; break;
832 case K_S_LEFT: c = K_S_RIGHT; break;
833 case K_C_LEFT: c = K_C_RIGHT; break;
834 case K_RIGHT: c = K_LEFT; break;
835 case K_S_RIGHT: c = K_S_LEFT; break;
836 case K_C_RIGHT: c = K_C_LEFT; break;
837 }
838#endif
839
840#ifdef FEAT_VISUAL
841 /*
842 * If 'keymodel' contains "startsel", may start selection. If it
843 * does, a CTRL-O and c will be stuffed, we need to get these
844 * characters.
845 */
846 if (ins_start_select(c))
847 continue;
848#endif
849
850 /*
851 * The big switch to handle a character in insert mode.
852 */
853 switch (c)
854 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000855 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 if (echeck_abbr(ESC + ABBR_OFF))
857 break;
858 /*FALLTHROUGH*/
859
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000860 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861#ifdef FEAT_CMDWIN
862 if (c == Ctrl_C && cmdwin_type != 0)
863 {
864 /* Close the cmdline window. */
865 cmdwin_result = K_IGNORE;
866 got_int = FALSE; /* don't stop executing autocommands et al. */
867 goto doESCkey;
868 }
869#endif
870
871#ifdef UNIX
872do_intr:
873#endif
874 /* when 'insertmode' set, and not halfway a mapping, don't leave
875 * Insert mode */
876 if (goto_im())
877 {
878 if (got_int)
879 {
880 (void)vgetc(); /* flush all buffers */
881 got_int = FALSE;
882 }
883 else
884 vim_beep();
885 break;
886 }
887doESCkey:
888 /*
889 * This is the ONLY return from edit()!
890 */
891 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
892 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000893 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 o_lnum = curwin->w_cursor.lnum;
895
Bram Moolenaar488c6512005-08-11 20:09:58 +0000896 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000897 {
898#ifdef FEAT_AUTOCMD
899 if (cmdchar != 'r' && cmdchar != 'v')
900 apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL,
901 FALSE, curbuf);
902#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 continue;
906
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000907 case Ctrl_Z: /* suspend when 'insertmode' set */
908 if (!p_im)
909 goto normalchar; /* insert CTRL-Z as normal char */
910 stuffReadbuff((char_u *)":st\r");
911 c = Ctrl_O;
912 /*FALLTHROUGH*/
913
914 case Ctrl_O: /* execute one command */
Bram Moolenaare344bea2005-09-01 20:46:49 +0000915#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000916 if (ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000917 goto docomplete;
918#endif
919 if (echeck_abbr(Ctrl_O + ABBR_OFF))
920 break;
921 ins_ctrl_o();
922 count = 0;
923 goto doESCkey;
924
Bram Moolenaar572cb562005-08-05 21:35:02 +0000925 case K_INS: /* toggle insert/replace mode */
926 case K_KINS:
927 ins_insert(replaceState);
928 break;
929
930 case K_SELECT: /* end of Select mode mapping - ignore */
931 break;
932
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000933#ifdef FEAT_SNIFF
934 case K_SNIFF: /* Sniff command received */
935 stuffcharReadbuff(K_SNIFF);
936 goto doESCkey;
937#endif
938
939 case K_HELP: /* Help key works like <ESC> <Help> */
940 case K_F1:
941 case K_XF1:
942 stuffcharReadbuff(K_HELP);
943 if (p_im)
944 need_start_insertmode = TRUE;
945 goto doESCkey;
946
947#ifdef FEAT_NETBEANS_INTG
948 case K_F21: /* NetBeans command */
949 ++no_mapping; /* don't map the next key hits */
950 i = safe_vgetc();
951 --no_mapping;
952 netbeans_keycommand(i);
953 break;
954#endif
955
956 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000957 case NUL:
958 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000959 /* For ^@ the trailing ESC will end the insert, unless there is an
960 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
962 && c != Ctrl_A && !p_im)
963 goto doESCkey; /* quit insert mode */
964 inserted_space = FALSE;
965 break;
966
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000967 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 ins_reg();
969 auto_format(FALSE, TRUE);
970 inserted_space = FALSE;
971 break;
972
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000973 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 ins_ctrl_g();
975 break;
976
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000977 case Ctrl_HAT: /* switch input mode and/or langmap */
978 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 break;
980
981#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000982 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983 if (!p_ari)
984 goto normalchar;
985 ins_ctrl_();
986 break;
987#endif
988
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000989 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
991 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
992 goto docomplete;
993#endif
994 /* FALLTHROUGH */
995
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000996 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997# ifdef FEAT_INS_EXPAND
998 if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
999 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001000 if (has_compl_option(FALSE))
1001 goto docomplete;
1002 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001003 }
1004# endif
1005 ins_shift(c, lastc);
1006 auto_format(FALSE, TRUE);
1007 inserted_space = FALSE;
1008 break;
1009
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001010 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 case K_KDEL:
1012 ins_del();
1013 auto_format(FALSE, TRUE);
1014 break;
1015
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001016 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 case Ctrl_H:
1018 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
1019 auto_format(FALSE, TRUE);
1020 break;
1021
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001022 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
1024 auto_format(FALSE, TRUE);
1025 break;
1026
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001027 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001028# ifdef FEAT_COMPL_FUNC
1029 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001030 if (ctrl_x_mode == CTRL_X_FUNCTION)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001031 goto docomplete;
1032# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
1034 auto_format(FALSE, TRUE);
1035 inserted_space = FALSE;
1036 break;
1037
1038#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001039 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 case K_LEFTMOUSE_NM:
1041 case K_LEFTDRAG:
1042 case K_LEFTRELEASE:
1043 case K_LEFTRELEASE_NM:
1044 case K_MIDDLEMOUSE:
1045 case K_MIDDLEDRAG:
1046 case K_MIDDLERELEASE:
1047 case K_RIGHTMOUSE:
1048 case K_RIGHTDRAG:
1049 case K_RIGHTRELEASE:
1050 case K_X1MOUSE:
1051 case K_X1DRAG:
1052 case K_X1RELEASE:
1053 case K_X2MOUSE:
1054 case K_X2DRAG:
1055 case K_X2RELEASE:
1056 ins_mouse(c);
1057 break;
1058
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001059 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 ins_mousescroll(FALSE);
1061 break;
1062
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001063 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 ins_mousescroll(TRUE);
1065 break;
1066#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +00001067#ifdef FEAT_GUI_TABLINE
1068 case K_TABLINE:
1069 case K_TABMENU:
1070 ins_tabline(c);
1071 break;
1072#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001074 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 break;
1076
Bram Moolenaar754b5602006-02-09 23:53:20 +00001077#ifdef FEAT_AUTOCMD
1078 case K_CURSORHOLD: /* Didn't type something for a while. */
1079 apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf);
1080 did_cursorhold = TRUE;
1081 break;
1082#endif
1083
Bram Moolenaar4770d092006-01-12 23:22:24 +00001084#ifdef FEAT_GUI_W32
1085 /* On Win32 ignore <M-F4>, we get it when closing the window was
1086 * cancelled. */
1087 case K_F4:
1088 if (mod_mask != MOD_MASK_ALT)
1089 goto normalchar;
1090 break;
1091#endif
1092
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093#ifdef FEAT_GUI
1094 case K_VER_SCROLLBAR:
1095 ins_scroll();
1096 break;
1097
1098 case K_HOR_SCROLLBAR:
1099 ins_horscroll();
1100 break;
1101#endif
1102
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001103 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 case K_S_HOME:
1106 case K_C_HOME:
1107 ins_home(c);
1108 break;
1109
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001110 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 case K_S_END:
1113 case K_C_END:
1114 ins_end(c);
1115 break;
1116
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001117 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001118 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1119 ins_s_left();
1120 else
1121 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122 break;
1123
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001124 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 case K_C_LEFT:
1126 ins_s_left();
1127 break;
1128
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001129 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001130 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1131 ins_s_right();
1132 else
1133 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 break;
1135
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001136 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 case K_C_RIGHT:
1138 ins_s_right();
1139 break;
1140
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001141 case K_UP: /* <Up> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001142#ifdef FEAT_INS_EXPAND
1143 if (pum_visible())
1144 goto docomplete;
1145#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001146 if (mod_mask & MOD_MASK_SHIFT)
1147 ins_pageup();
1148 else
1149 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150 break;
1151
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001152 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 case K_PAGEUP:
1154 case K_KPAGEUP:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001155#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001156 if (pum_visible())
1157 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001158#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 ins_pageup();
1160 break;
1161
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001162 case K_DOWN: /* <Down> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001163#ifdef FEAT_INS_EXPAND
1164 if (pum_visible())
1165 goto docomplete;
1166#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001167 if (mod_mask & MOD_MASK_SHIFT)
1168 ins_pagedown();
1169 else
1170 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171 break;
1172
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001173 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174 case K_PAGEDOWN:
1175 case K_KPAGEDOWN:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001176#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001177 if (pum_visible())
1178 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001179#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180 ins_pagedown();
1181 break;
1182
1183#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001184 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185 ins_drop();
1186 break;
1187#endif
1188
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001189 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190 c = TAB;
1191 /* FALLTHROUGH */
1192
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001193 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1195 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
1196 goto docomplete;
1197#endif
1198 inserted_space = FALSE;
1199 if (ins_tab())
1200 goto normalchar; /* insert TAB as a normal char */
1201 auto_format(FALSE, TRUE);
1202 break;
1203
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001204 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 c = CAR;
1206 /* FALLTHROUGH */
1207 case CAR:
1208 case NL:
1209#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
1210 /* In a quickfix window a <CR> jumps to the error under the
1211 * cursor. */
1212 if (bt_quickfix(curbuf) && c == CAR)
1213 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001214 if (curwin->w_llist_ref == NULL) /* quickfix window */
1215 do_cmdline_cmd((char_u *)".cc");
1216 else /* location list window */
1217 do_cmdline_cmd((char_u *)".ll");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 break;
1219 }
1220#endif
1221#ifdef FEAT_CMDWIN
1222 if (cmdwin_type != 0)
1223 {
1224 /* Execute the command in the cmdline window. */
1225 cmdwin_result = CAR;
1226 goto doESCkey;
1227 }
1228#endif
1229 if (ins_eol(c) && !p_im)
1230 goto doESCkey; /* out of memory */
1231 auto_format(FALSE, FALSE);
1232 inserted_space = FALSE;
1233 break;
1234
1235#if defined(FEAT_DIGRAPHS) || defined (FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001236 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237# ifdef FEAT_INS_EXPAND
1238 if (ctrl_x_mode == CTRL_X_DICTIONARY)
1239 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001240 if (has_compl_option(TRUE))
1241 goto docomplete;
1242 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 }
1244# endif
1245# ifdef FEAT_DIGRAPHS
1246 c = ins_digraph();
1247 if (c == NUL)
1248 break;
1249# endif
1250 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001251#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252
1253#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001254 case Ctrl_X: /* Enter CTRL-X mode */
1255 ins_ctrl_x();
1256 break;
1257
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001258 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 if (ctrl_x_mode != CTRL_X_TAGS)
1260 goto normalchar;
1261 goto docomplete;
1262
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001263 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264 if (ctrl_x_mode != CTRL_X_FILES)
1265 goto normalchar;
1266 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001267
1268 case 's': /* Spelling completion after ^X */
1269 case Ctrl_S:
1270 if (ctrl_x_mode != CTRL_X_SPELL)
1271 goto normalchar;
1272 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273#endif
1274
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001275 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276#ifdef FEAT_INS_EXPAND
1277 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
1278#endif
1279 {
1280 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1281 if (p_im)
1282 {
1283 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1284 break;
1285 goto doESCkey;
1286 }
1287 goto normalchar;
1288 }
1289#ifdef FEAT_INS_EXPAND
1290 /* FALLTHROUGH */
1291
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001292 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 case Ctrl_N:
1294 /* if 'complete' is empty then plain ^P is no longer special,
1295 * but it is under other ^X modes */
1296 if (*curbuf->b_p_cpt == NUL
1297 && ctrl_x_mode != 0
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001298 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 goto normalchar;
1300
1301docomplete:
1302 if (ins_complete(c) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001303 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304 break;
1305#endif /* FEAT_INS_EXPAND */
1306
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001307 case Ctrl_Y: /* copy from previous line or scroll down */
1308 case Ctrl_E: /* copy from next line or scroll up */
1309 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 break;
1311
1312 default:
1313#ifdef UNIX
1314 if (c == intr_char) /* special interrupt char */
1315 goto do_intr;
1316#endif
1317
1318 /*
1319 * Insert a nomal character.
1320 */
1321normalchar:
1322#ifdef FEAT_SMARTINDENT
1323 /* Try to perform smart-indenting. */
1324 ins_try_si(c);
1325#endif
1326
1327 if (c == ' ')
1328 {
1329 inserted_space = TRUE;
1330#ifdef FEAT_CINDENT
1331 if (inindent(0))
1332 can_cindent = FALSE;
1333#endif
1334 if (Insstart_blank_vcol == MAXCOL
1335 && curwin->w_cursor.lnum == Insstart.lnum)
1336 Insstart_blank_vcol = get_nolist_virtcol();
1337 }
1338
1339 if (vim_iswordc(c) || !echeck_abbr(
1340#ifdef FEAT_MBYTE
1341 /* Add ABBR_OFF for characters above 0x100, this is
1342 * what check_abbr() expects. */
1343 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1344#endif
1345 c))
1346 {
1347 insert_special(c, FALSE, FALSE);
1348#ifdef FEAT_RIGHTLEFT
1349 revins_legal++;
1350 revins_chars++;
1351#endif
1352 }
1353
1354 auto_format(FALSE, TRUE);
1355
1356#ifdef FEAT_FOLDING
1357 /* When inserting a character the cursor line must never be in a
1358 * closed fold. */
1359 foldOpenCursor();
1360#endif
1361 break;
1362 } /* end of switch (c) */
1363
1364 /* If the cursor was moved we didn't just insert a space */
1365 if (arrow_used)
1366 inserted_space = FALSE;
1367
1368#ifdef FEAT_CINDENT
1369 if (can_cindent && cindent_on()
1370# ifdef FEAT_INS_EXPAND
1371 && ctrl_x_mode == 0
1372# endif
1373 )
1374 {
1375force_cindent:
1376 /*
1377 * Indent now if a key was typed that is in 'cinkeys'.
1378 */
1379 if (in_cinkeys(c, ' ', line_is_white))
1380 {
1381 if (stop_arrow() == OK)
1382 /* re-indent the current line */
1383 do_c_expr_indent();
1384 }
1385 }
1386#endif /* FEAT_CINDENT */
1387
1388 } /* for (;;) */
1389 /* NOTREACHED */
1390}
1391
1392/*
1393 * Redraw for Insert mode.
1394 * This is postponed until getting the next character to make '$' in the 'cpo'
1395 * option work correctly.
1396 * Only redraw when there are no characters available. This speeds up
1397 * inserting sequences of characters (e.g., for CTRL-R).
1398 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001399/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400 static void
Bram Moolenaar754b5602006-02-09 23:53:20 +00001401ins_redraw(ready)
1402 int ready; /* not busy with something */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403{
1404 if (!char_avail())
1405 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00001406#ifdef FEAT_AUTOCMD
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001407 /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
1408 * visible, the command might delete it. */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001409 if (ready && has_cursormovedI()
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001410 && !equalpos(last_cursormoved, curwin->w_cursor)
1411# ifdef FEAT_INS_EXPAND
1412 && !pum_visible()
1413# endif
1414 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00001415 {
1416 apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, FALSE, curbuf);
1417 last_cursormoved = curwin->w_cursor;
1418 }
1419#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001420 if (must_redraw)
1421 update_screen(0);
1422 else if (clear_cmdline || redraw_cmdline)
1423 showmode(); /* clear cmdline and show mode */
1424 showruler(FALSE);
1425 setcursor();
1426 emsg_on_display = FALSE; /* may remove error message now */
1427 }
1428}
1429
1430/*
1431 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1432 */
1433 static void
1434ins_ctrl_v()
1435{
1436 int c;
1437
1438 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001439 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001440
1441 if (redrawing() && !char_avail())
1442 edit_putchar('^', TRUE);
1443 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1444
1445#ifdef FEAT_CMDL_INFO
1446 add_to_showcmd_c(Ctrl_V);
1447#endif
1448
1449 c = get_literal();
1450#ifdef FEAT_CMDL_INFO
1451 clear_showcmd();
1452#endif
1453 insert_special(c, FALSE, TRUE);
1454#ifdef FEAT_RIGHTLEFT
1455 revins_chars++;
1456 revins_legal++;
1457#endif
1458}
1459
1460/*
1461 * Put a character directly onto the screen. It's not stored in a buffer.
1462 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1463 */
1464static int pc_status;
1465#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1466#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1467#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1468#define PC_STATUS_SET 3 /* pc_bytes was filled */
1469#ifdef FEAT_MBYTE
1470static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1471#else
1472static char_u pc_bytes[2]; /* saved bytes */
1473#endif
1474static int pc_attr;
1475static int pc_row;
1476static int pc_col;
1477
1478 void
1479edit_putchar(c, highlight)
1480 int c;
1481 int highlight;
1482{
1483 int attr;
1484
1485 if (ScreenLines != NULL)
1486 {
1487 update_topline(); /* just in case w_topline isn't valid */
1488 validate_cursor();
1489 if (highlight)
1490 attr = hl_attr(HLF_8);
1491 else
1492 attr = 0;
1493 pc_row = W_WINROW(curwin) + curwin->w_wrow;
1494 pc_col = W_WINCOL(curwin);
1495#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1496 pc_status = PC_STATUS_UNSET;
1497#endif
1498#ifdef FEAT_RIGHTLEFT
1499 if (curwin->w_p_rl)
1500 {
1501 pc_col += W_WIDTH(curwin) - 1 - curwin->w_wcol;
1502# ifdef FEAT_MBYTE
1503 if (has_mbyte)
1504 {
1505 int fix_col = mb_fix_col(pc_col, pc_row);
1506
1507 if (fix_col != pc_col)
1508 {
1509 screen_putchar(' ', pc_row, fix_col, attr);
1510 --curwin->w_wcol;
1511 pc_status = PC_STATUS_RIGHT;
1512 }
1513 }
1514# endif
1515 }
1516 else
1517#endif
1518 {
1519 pc_col += curwin->w_wcol;
1520#ifdef FEAT_MBYTE
1521 if (mb_lefthalve(pc_row, pc_col))
1522 pc_status = PC_STATUS_LEFT;
1523#endif
1524 }
1525
1526 /* save the character to be able to put it back */
1527#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1528 if (pc_status == PC_STATUS_UNSET)
1529#endif
1530 {
1531 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1532 pc_status = PC_STATUS_SET;
1533 }
1534 screen_putchar(c, pc_row, pc_col, attr);
1535 }
1536}
1537
1538/*
1539 * Undo the previous edit_putchar().
1540 */
1541 void
1542edit_unputchar()
1543{
1544 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1545 {
1546#if defined(FEAT_MBYTE)
1547 if (pc_status == PC_STATUS_RIGHT)
1548 ++curwin->w_wcol;
1549 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
1550 redrawWinline(curwin->w_cursor.lnum, FALSE);
1551 else
1552#endif
1553 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1554 }
1555}
1556
1557/*
1558 * Called when p_dollar is set: display a '$' at the end of the changed text
1559 * Only works when cursor is in the line that changes.
1560 */
1561 void
1562display_dollar(col)
1563 colnr_T col;
1564{
1565 colnr_T save_col;
1566
1567 if (!redrawing())
1568 return;
1569
1570 cursor_off();
1571 save_col = curwin->w_cursor.col;
1572 curwin->w_cursor.col = col;
1573#ifdef FEAT_MBYTE
1574 if (has_mbyte)
1575 {
1576 char_u *p;
1577
1578 /* If on the last byte of a multi-byte move to the first byte. */
1579 p = ml_get_curline();
1580 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1581 }
1582#endif
1583 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
1584 if (curwin->w_wcol < W_WIDTH(curwin))
1585 {
1586 edit_putchar('$', FALSE);
1587 dollar_vcol = curwin->w_virtcol;
1588 }
1589 curwin->w_cursor.col = save_col;
1590}
1591
1592/*
1593 * Call this function before moving the cursor from the normal insert position
1594 * in insert mode.
1595 */
1596 static void
1597undisplay_dollar()
1598{
1599 if (dollar_vcol)
1600 {
1601 dollar_vcol = 0;
1602 redrawWinline(curwin->w_cursor.lnum, FALSE);
1603 }
1604}
1605
1606/*
1607 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1608 * Keep the cursor on the same character.
1609 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1610 * type == INDENT_DEC decrease indent (for CTRL-D)
1611 * type == INDENT_SET set indent to "amount"
1612 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1613 */
1614 void
1615change_indent(type, amount, round, replaced)
1616 int type;
1617 int amount;
1618 int round;
1619 int replaced; /* replaced character, put on replace stack */
1620{
1621 int vcol;
1622 int last_vcol;
1623 int insstart_less; /* reduction for Insstart.col */
1624 int new_cursor_col;
1625 int i;
1626 char_u *ptr;
1627 int save_p_list;
1628 int start_col;
1629 colnr_T vc;
1630#ifdef FEAT_VREPLACE
1631 colnr_T orig_col = 0; /* init for GCC */
1632 char_u *new_line, *orig_line = NULL; /* init for GCC */
1633
1634 /* VREPLACE mode needs to know what the line was like before changing */
1635 if (State & VREPLACE_FLAG)
1636 {
1637 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1638 orig_col = curwin->w_cursor.col;
1639 }
1640#endif
1641
1642 /* for the following tricks we don't want list mode */
1643 save_p_list = curwin->w_p_list;
1644 curwin->w_p_list = FALSE;
1645 vc = getvcol_nolist(&curwin->w_cursor);
1646 vcol = vc;
1647
1648 /*
1649 * For Replace mode we need to fix the replace stack later, which is only
1650 * possible when the cursor is in the indent. Remember the number of
1651 * characters before the cursor if it's possible.
1652 */
1653 start_col = curwin->w_cursor.col;
1654
1655 /* determine offset from first non-blank */
1656 new_cursor_col = curwin->w_cursor.col;
1657 beginline(BL_WHITE);
1658 new_cursor_col -= curwin->w_cursor.col;
1659
1660 insstart_less = curwin->w_cursor.col;
1661
1662 /*
1663 * If the cursor is in the indent, compute how many screen columns the
1664 * cursor is to the left of the first non-blank.
1665 */
1666 if (new_cursor_col < 0)
1667 vcol = get_indent() - vcol;
1668
1669 if (new_cursor_col > 0) /* can't fix replace stack */
1670 start_col = -1;
1671
1672 /*
1673 * Set the new indent. The cursor will be put on the first non-blank.
1674 */
1675 if (type == INDENT_SET)
1676 (void)set_indent(amount, SIN_CHANGED);
1677 else
1678 {
1679#ifdef FEAT_VREPLACE
1680 int save_State = State;
1681
1682 /* Avoid being called recursively. */
1683 if (State & VREPLACE_FLAG)
1684 State = INSERT;
1685#endif
1686 shift_line(type == INDENT_DEC, round, 1);
1687#ifdef FEAT_VREPLACE
1688 State = save_State;
1689#endif
1690 }
1691 insstart_less -= curwin->w_cursor.col;
1692
1693 /*
1694 * Try to put cursor on same character.
1695 * If the cursor is at or after the first non-blank in the line,
1696 * compute the cursor column relative to the column of the first
1697 * non-blank character.
1698 * If we are not in insert mode, leave the cursor on the first non-blank.
1699 * If the cursor is before the first non-blank, position it relative
1700 * to the first non-blank, counted in screen columns.
1701 */
1702 if (new_cursor_col >= 0)
1703 {
1704 /*
1705 * When changing the indent while the cursor is touching it, reset
1706 * Insstart_col to 0.
1707 */
1708 if (new_cursor_col == 0)
1709 insstart_less = MAXCOL;
1710 new_cursor_col += curwin->w_cursor.col;
1711 }
1712 else if (!(State & INSERT))
1713 new_cursor_col = curwin->w_cursor.col;
1714 else
1715 {
1716 /*
1717 * Compute the screen column where the cursor should be.
1718 */
1719 vcol = get_indent() - vcol;
1720 curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
1721
1722 /*
1723 * Advance the cursor until we reach the right screen column.
1724 */
1725 vcol = last_vcol = 0;
1726 new_cursor_col = -1;
1727 ptr = ml_get_curline();
1728 while (vcol <= (int)curwin->w_virtcol)
1729 {
1730 last_vcol = vcol;
1731#ifdef FEAT_MBYTE
1732 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001733 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 else
1735#endif
1736 ++new_cursor_col;
1737 vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
1738 }
1739 vcol = last_vcol;
1740
1741 /*
1742 * May need to insert spaces to be able to position the cursor on
1743 * the right screen column.
1744 */
1745 if (vcol != (int)curwin->w_virtcol)
1746 {
1747 curwin->w_cursor.col = new_cursor_col;
1748 i = (int)curwin->w_virtcol - vcol;
1749 ptr = alloc(i + 1);
1750 if (ptr != NULL)
1751 {
1752 new_cursor_col += i;
1753 ptr[i] = NUL;
1754 while (--i >= 0)
1755 ptr[i] = ' ';
1756 ins_str(ptr);
1757 vim_free(ptr);
1758 }
1759 }
1760
1761 /*
1762 * When changing the indent while the cursor is in it, reset
1763 * Insstart_col to 0.
1764 */
1765 insstart_less = MAXCOL;
1766 }
1767
1768 curwin->w_p_list = save_p_list;
1769
1770 if (new_cursor_col <= 0)
1771 curwin->w_cursor.col = 0;
1772 else
1773 curwin->w_cursor.col = new_cursor_col;
1774 curwin->w_set_curswant = TRUE;
1775 changed_cline_bef_curs();
1776
1777 /*
1778 * May have to adjust the start of the insert.
1779 */
1780 if (State & INSERT)
1781 {
1782 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1783 {
1784 if ((int)Insstart.col <= insstart_less)
1785 Insstart.col = 0;
1786 else
1787 Insstart.col -= insstart_less;
1788 }
1789 if ((int)ai_col <= insstart_less)
1790 ai_col = 0;
1791 else
1792 ai_col -= insstart_less;
1793 }
1794
1795 /*
1796 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1797 * If the number of characters before the cursor decreased, need to pop a
1798 * few characters from the replace stack.
1799 * If the number of characters before the cursor increased, need to push a
1800 * few NULs onto the replace stack.
1801 */
1802 if (REPLACE_NORMAL(State) && start_col >= 0)
1803 {
1804 while (start_col > (int)curwin->w_cursor.col)
1805 {
1806 replace_join(0); /* remove a NUL from the replace stack */
1807 --start_col;
1808 }
1809 while (start_col < (int)curwin->w_cursor.col || replaced)
1810 {
1811 replace_push(NUL);
1812 if (replaced)
1813 {
1814 replace_push(replaced);
1815 replaced = NUL;
1816 }
1817 ++start_col;
1818 }
1819 }
1820
1821#ifdef FEAT_VREPLACE
1822 /*
1823 * For VREPLACE mode, we also have to fix the replace stack. In this case
1824 * it is always possible because we backspace over the whole line and then
1825 * put it back again the way we wanted it.
1826 */
1827 if (State & VREPLACE_FLAG)
1828 {
1829 /* If orig_line didn't allocate, just return. At least we did the job,
1830 * even if you can't backspace. */
1831 if (orig_line == NULL)
1832 return;
1833
1834 /* Save new line */
1835 new_line = vim_strsave(ml_get_curline());
1836 if (new_line == NULL)
1837 return;
1838
1839 /* We only put back the new line up to the cursor */
1840 new_line[curwin->w_cursor.col] = NUL;
1841
1842 /* Put back original line */
1843 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1844 curwin->w_cursor.col = orig_col;
1845
1846 /* Backspace from cursor to start of line */
1847 backspace_until_column(0);
1848
1849 /* Insert new stuff into line again */
1850 ins_bytes(new_line);
1851
1852 vim_free(new_line);
1853 }
1854#endif
1855}
1856
1857/*
1858 * Truncate the space at the end of a line. This is to be used only in an
1859 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1860 * modes.
1861 */
1862 void
1863truncate_spaces(line)
1864 char_u *line;
1865{
1866 int i;
1867
1868 /* find start of trailing white space */
1869 for (i = (int)STRLEN(line) - 1; i >= 0 && vim_iswhite(line[i]); i--)
1870 {
1871 if (State & REPLACE_FLAG)
1872 replace_join(0); /* remove a NUL from the replace stack */
1873 }
1874 line[i + 1] = NUL;
1875}
1876
1877#if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \
1878 || defined(FEAT_COMMENTS) || defined(PROTO)
1879/*
1880 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1881 * modes correctly. May also be used when not in insert mode at all.
1882 */
1883 void
1884backspace_until_column(col)
1885 int col;
1886{
1887 while ((int)curwin->w_cursor.col > col)
1888 {
1889 curwin->w_cursor.col--;
1890 if (State & REPLACE_FLAG)
1891 replace_do_bs();
1892 else
1893 (void)del_char(FALSE);
1894 }
1895}
1896#endif
1897
1898#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1899/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001900 * CTRL-X pressed in Insert mode.
1901 */
1902 static void
1903ins_ctrl_x()
1904{
1905 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1906 * CTRL-V works like CTRL-N */
1907 if (ctrl_x_mode != CTRL_X_CMDLINE)
1908 {
1909 /* if the next ^X<> won't ADD nothing, then reset
1910 * compl_cont_status */
1911 if (compl_cont_status & CONT_N_ADDS)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001912 compl_cont_status |= CONT_INTRPT;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001913 else
1914 compl_cont_status = 0;
1915 /* We're not sure which CTRL-X mode it will be yet */
1916 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1917 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1918 edit_submode_pre = NULL;
1919 showmode();
1920 }
1921}
1922
1923/*
1924 * Return TRUE if the 'dict' or 'tsr' option can be used.
1925 */
1926 static int
1927has_compl_option(dict_opt)
1928 int dict_opt;
1929{
Bram Moolenaar0b238792006-03-02 22:49:12 +00001930 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00001931# ifdef FEAT_SPELL
1932 && !curwin->w_p_spell
1933# endif
1934 )
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001935 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
1936 {
1937 ctrl_x_mode = 0;
1938 edit_submode = NULL;
1939 msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
1940 : (char_u *)_("'thesaurus' option is empty"),
1941 hl_attr(HLF_E));
1942 if (emsg_silent == 0)
1943 {
1944 vim_beep();
1945 setcursor();
1946 out_flush();
1947 ui_delay(2000L, FALSE);
1948 }
1949 return FALSE;
1950 }
1951 return TRUE;
1952}
1953
1954/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
1956 * This depends on the current mode.
1957 */
1958 int
1959vim_is_ctrl_x_key(c)
1960 int c;
1961{
1962 /* Always allow ^R - let it's results then be checked */
1963 if (c == Ctrl_R)
1964 return TRUE;
1965
Bram Moolenaare3226be2005-12-18 22:10:00 +00001966 /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001967 if (ins_compl_pum_key(c))
Bram Moolenaare3226be2005-12-18 22:10:00 +00001968 return TRUE;
1969
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 switch (ctrl_x_mode)
1971 {
1972 case 0: /* Not in any CTRL-X mode */
1973 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
1974 case CTRL_X_NOT_DEFINED_YET:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001975 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1977 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
1978 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
Bram Moolenaar488c6512005-08-11 20:09:58 +00001979 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
1980 || c == Ctrl_S || c == 's');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001981 case CTRL_X_SCROLL:
1982 return (c == Ctrl_Y || c == Ctrl_E);
1983 case CTRL_X_WHOLE_LINE:
1984 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
1985 case CTRL_X_FILES:
1986 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
1987 case CTRL_X_DICTIONARY:
1988 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
1989 case CTRL_X_THESAURUS:
1990 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
1991 case CTRL_X_TAGS:
1992 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
1993#ifdef FEAT_FIND_ID
1994 case CTRL_X_PATH_PATTERNS:
1995 return (c == Ctrl_P || c == Ctrl_N);
1996 case CTRL_X_PATH_DEFINES:
1997 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
1998#endif
1999 case CTRL_X_CMDLINE:
2000 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
2001 || c == Ctrl_X);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002002#ifdef FEAT_COMPL_FUNC
2003 case CTRL_X_FUNCTION:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002004 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002005 case CTRL_X_OMNI:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002006 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002007#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002008 case CTRL_X_SPELL:
2009 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002010 }
2011 EMSG(_(e_internal));
2012 return FALSE;
2013}
2014
2015/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002016 * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017 * case of the originally typed text is used, and the case of the completed
2018 * text is infered, ie this tries to work out what case you probably wanted
2019 * the rest of the word to be in -- webb
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002020 * TODO: make this work for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021 */
2022 int
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002023ins_compl_add_infercase(str, len, icase, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 char_u *str;
2025 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002026 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 char_u *fname;
2028 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002029 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030{
2031 int has_lower = FALSE;
2032 int was_letter = FALSE;
2033 int idx;
2034
2035 if (p_ic && curbuf->b_p_inf && len < IOSIZE)
2036 {
2037 /* Infer case of completed part -- webb */
2038 /* Use IObuff, str would change text in buffer! */
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002039 vim_strncpy(IObuff, str, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040
2041 /* Rule 1: Were any chars converted to lower? */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002042 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002044 if (islower(compl_orig_text[idx]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002045 {
2046 has_lower = TRUE;
2047 if (isupper(IObuff[idx]))
2048 {
2049 /* Rule 1 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002050 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
2052 break;
2053 }
2054 }
2055 }
2056
2057 /*
2058 * Rule 2: No lower case, 2nd consecutive letter converted to
2059 * upper case.
2060 */
2061 if (!has_lower)
2062 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002063 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002065 if (was_letter && isupper(compl_orig_text[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 && islower(IObuff[idx]))
2067 {
2068 /* Rule 2 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002069 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
2071 break;
2072 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002073 was_letter = isalpha(compl_orig_text[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 }
2075 }
2076
2077 /* Copy the original case of the part we typed */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002078 STRNCPY(IObuff, compl_orig_text, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002080 return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
2081 flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082 }
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002083 return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084}
2085
2086/*
2087 * Add a match to the list of matches.
2088 * If the given string is already in the list of completions, then return
Bram Moolenaar572cb562005-08-05 21:35:02 +00002089 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002090 * maybe because alloc() returns NULL, then FAIL is returned.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002092 static int
2093ins_compl_add(str, len, icase, fname, cptext, cdir, flags, dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 char_u *str;
2095 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002096 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 char_u *fname;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002098 char_u **cptext; /* extra text for popup menu or NULL */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002099 int cdir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002100 int flags;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002101 int dup; /* accept duplicate match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002103 compl_T *match;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002104 int dir = (cdir == 0 ? compl_direction : cdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105
2106 ui_breakcheck();
2107 if (got_int)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002108 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 if (len < 0)
2110 len = (int)STRLEN(str);
2111
2112 /*
2113 * If the same match is already present, don't add it.
2114 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002115 if (compl_first_match != NULL && !dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002117 match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 do
2119 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002120 if ( !(match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002121 && ins_compl_equal(match, str, len)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002122 && match->cp_str[len] == NUL)
2123 return NOTDONE;
2124 match = match->cp_next;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002125 } while (match != NULL && match != compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 }
2127
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002128 /* Remove any popup menu before changing the list of matches. */
2129 ins_compl_del_pum();
2130
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 /*
2132 * Allocate a new match structure.
2133 * Copy the values to the new match structure.
2134 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002135 match = (compl_T *)alloc_clear((unsigned)sizeof(compl_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 if (match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002137 return FAIL;
2138 match->cp_number = -1;
2139 if (flags & ORIGINAL_TEXT)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002140 match->cp_number = 0;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002141 if ((match->cp_str = vim_strnsave(str, len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142 {
2143 vim_free(match);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002144 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002146 match->cp_icase = icase;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002147
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 /* match-fname is:
Bram Moolenaar572cb562005-08-05 21:35:02 +00002149 * - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002150 * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
2151 * - NULL otherwise. --Acevedo */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002152 if (fname != NULL
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002153 && compl_curr_match != NULL
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002154 && compl_curr_match->cp_fname != NULL
2155 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002156 match->cp_fname = compl_curr_match->cp_fname;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002157 else if (fname != NULL)
2158 {
2159 match->cp_fname = vim_strsave(fname);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002160 flags |= FREE_FNAME;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002161 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 else
Bram Moolenaar572cb562005-08-05 21:35:02 +00002163 match->cp_fname = NULL;
2164 match->cp_flags = flags;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002165
2166 if (cptext != NULL)
2167 {
2168 int i;
2169
2170 for (i = 0; i < CPT_COUNT; ++i)
2171 if (cptext[i] != NULL && *cptext[i] != NUL)
2172 match->cp_text[i] = vim_strsave(cptext[i]);
2173 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174
2175 /*
2176 * Link the new match structure in the list of matches.
2177 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002178 if (compl_first_match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002179 match->cp_next = match->cp_prev = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 else if (dir == FORWARD)
2181 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002182 match->cp_next = compl_curr_match->cp_next;
2183 match->cp_prev = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 }
2185 else /* BACKWARD */
2186 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002187 match->cp_next = compl_curr_match;
2188 match->cp_prev = compl_curr_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002189 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002190 if (match->cp_next)
2191 match->cp_next->cp_prev = match;
2192 if (match->cp_prev)
2193 match->cp_prev->cp_next = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002194 else /* if there's nothing before, it is the first match */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002195 compl_first_match = match;
2196 compl_curr_match = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002198 /*
2199 * Find the longest common string if still doing that.
2200 */
2201 if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
2202 ins_compl_longest_match(match);
2203
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204 return OK;
2205}
2206
2207/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002208 * Return TRUE if "str[len]" matches with match->cp_str, considering
2209 * match->cp_icase.
2210 */
2211 static int
2212ins_compl_equal(match, str, len)
2213 compl_T *match;
2214 char_u *str;
2215 int len;
2216{
2217 if (match->cp_icase)
2218 return STRNICMP(match->cp_str, str, (size_t)len) == 0;
2219 return STRNCMP(match->cp_str, str, (size_t)len) == 0;
2220}
2221
2222/*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002223 * Reduce the longest common string for match "match".
2224 */
2225 static void
2226ins_compl_longest_match(match)
2227 compl_T *match;
2228{
2229 char_u *p, *s;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002230 int c1, c2;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002231 int had_match;
2232
2233 if (compl_leader == NULL)
2234 /* First match, use it as a whole. */
2235 compl_leader = vim_strsave(match->cp_str);
2236 else
2237 {
2238 /* Reduce the text if this match differs from compl_leader. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002239 p = compl_leader;
2240 s = match->cp_str;
2241 while (*p != NUL)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002242 {
2243#ifdef FEAT_MBYTE
2244 if (has_mbyte)
2245 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002246 c1 = mb_ptr2char(p);
2247 c2 = mb_ptr2char(s);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002248 }
2249 else
2250#endif
2251 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002252 c1 = *p;
2253 c2 = *s;
2254 }
2255 if (match->cp_icase ? (MB_TOLOWER(c1) != MB_TOLOWER(c2))
2256 : (c1 != c2))
2257 break;
2258#ifdef FEAT_MBYTE
2259 if (has_mbyte)
2260 {
2261 mb_ptr_adv(p);
2262 mb_ptr_adv(s);
2263 }
2264 else
2265#endif
2266 {
2267 ++p;
2268 ++s;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002269 }
2270 }
2271
2272 if (*p != NUL)
2273 {
2274 /* Leader was shortened, need to change the inserted text. */
2275 *p = NUL;
2276 had_match = (curwin->w_cursor.col > compl_col);
2277 ins_compl_delete();
2278 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2279 ins_redraw(FALSE);
2280
2281 /* When the match isn't there (to avoid matching itself) remove it
2282 * again after redrawing. */
2283 if (!had_match)
2284 ins_compl_delete();
2285 }
2286
2287 compl_used_match = FALSE;
2288 }
2289}
2290
2291/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 * Add an array of matches to the list of matches.
2293 * Frees matches[].
2294 */
2295 static void
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002296ins_compl_add_matches(num_matches, matches, icase)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 int num_matches;
2298 char_u **matches;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002299 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300{
2301 int i;
2302 int add_r = OK;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002303 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304
Bram Moolenaar572cb562005-08-05 21:35:02 +00002305 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002306 if ((add_r = ins_compl_add(matches[i], -1, icase,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002307 NULL, NULL, dir, 0, FALSE)) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 /* if dir was BACKWARD then honor it just once */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002309 dir = FORWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 FreeWild(num_matches, matches);
2311}
2312
2313/* Make the completion list cyclic.
2314 * Return the number of matches (excluding the original).
2315 */
2316 static int
2317ins_compl_make_cyclic()
2318{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002319 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 int count = 0;
2321
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002322 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 {
2324 /*
2325 * Find the end of the list.
2326 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002327 match = compl_first_match;
2328 /* there's always an entry for the compl_orig_text, it doesn't count. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002329 while (match->cp_next != NULL && match->cp_next != compl_first_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002331 match = match->cp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 ++count;
2333 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002334 match->cp_next = compl_first_match;
2335 compl_first_match->cp_prev = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 }
2337 return count;
2338}
2339
Bram Moolenaara94bc432006-03-10 21:42:59 +00002340/*
2341 * Start completion for the complete() function.
2342 * "startcol" is where the matched text starts (1 is first column).
2343 * "list" is the list of matches.
2344 */
2345 void
2346set_completion(startcol, list)
2347 int startcol;
2348 list_T *list;
2349{
2350 /* If already doing completions stop it. */
2351 if (ctrl_x_mode != 0)
2352 ins_compl_prep(' ');
2353 ins_compl_clear();
2354
2355 if (stop_arrow() == FAIL)
2356 return;
2357
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002358 if (startcol > (int)curwin->w_cursor.col)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002359 startcol = curwin->w_cursor.col;
2360 compl_col = startcol;
2361 compl_length = curwin->w_cursor.col - startcol;
2362 /* compl_pattern doesn't need to be set */
2363 compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
2364 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002365 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002366 return;
2367
2368 /* Handle like dictionary completion. */
2369 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2370
2371 ins_compl_add_list(list);
2372 compl_matches = ins_compl_make_cyclic();
2373 compl_started = TRUE;
2374 compl_used_match = TRUE;
2375
2376 compl_curr_match = compl_first_match;
2377 ins_complete(Ctrl_N);
2378 out_flush();
2379}
2380
2381
Bram Moolenaar9372a112005-12-06 19:59:18 +00002382/* "compl_match_array" points the currently displayed list of entries in the
2383 * popup menu. It is NULL when there is no popup menu. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002384static pumitem_T *compl_match_array = NULL;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002385static int compl_match_arraysize;
2386
2387/*
2388 * Update the screen and when there is any scrolling remove the popup menu.
2389 */
2390 static void
2391ins_compl_upd_pum()
2392{
2393 int h;
2394
2395 if (compl_match_array != NULL)
2396 {
2397 h = curwin->w_cline_height;
2398 update_screen(0);
2399 if (h != curwin->w_cline_height)
2400 ins_compl_del_pum();
2401 }
2402}
2403
2404/*
2405 * Remove any popup menu.
2406 */
2407 static void
2408ins_compl_del_pum()
2409{
2410 if (compl_match_array != NULL)
2411 {
2412 pum_undisplay();
2413 vim_free(compl_match_array);
2414 compl_match_array = NULL;
2415 }
2416}
2417
2418/*
2419 * Return TRUE if the popup menu should be displayed.
2420 */
2421 static int
2422pum_wanted()
2423{
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002424 /* 'completeopt' must contain "menu" or "menuone" */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002425 if (vim_strchr(p_cot, 'm') == NULL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002426 return FALSE;
2427
2428 /* The display looks bad on a B&W display. */
2429 if (t_colors < 8
2430#ifdef FEAT_GUI
2431 && !gui.in_use
2432#endif
2433 )
2434 return FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +00002435 return TRUE;
2436}
2437
2438/*
2439 * Return TRUE if there are two or more matches to be shown in the popup menu.
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002440 * One if 'completopt' contains "menuone".
Bram Moolenaara6557602006-02-04 22:43:20 +00002441 */
2442 static int
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002443pum_enough_matches()
Bram Moolenaara6557602006-02-04 22:43:20 +00002444{
2445 compl_T *compl;
2446 int i;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002447
2448 /* Don't display the popup menu if there are no matches or there is only
2449 * one (ignoring the original text). */
2450 compl = compl_first_match;
2451 i = 0;
2452 do
2453 {
2454 if (compl == NULL
2455 || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
2456 break;
2457 compl = compl->cp_next;
2458 } while (compl != compl_first_match);
2459
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002460 if (strstr((char *)p_cot, "menuone") != NULL)
2461 return (i >= 1);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002462 return (i >= 2);
2463}
2464
2465/*
2466 * Show the popup menu for the list of matches.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002467 * Also adjusts "compl_shown_match" to an entry that is actually displayed.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002468 */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002469 void
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002470ins_compl_show_pum()
2471{
2472 compl_T *compl;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002473 compl_T *shown_compl = NULL;
2474 int did_find_shown_match = FALSE;
2475 int shown_match_ok = FALSE;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002476 int i;
2477 int cur = -1;
2478 colnr_T col;
Bram Moolenaara6557602006-02-04 22:43:20 +00002479 int lead_len = 0;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002480
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002481 if (!pum_wanted() || !pum_enough_matches())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002482 return;
2483
Bram Moolenaar433f7c82006-03-21 21:29:36 +00002484#if defined(FEAT_EVAL)
2485 /* Dirty hard-coded hack: remove any matchparen highlighting. */
2486 do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|3match none|endif");
2487#endif
2488
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002489 /* Update the screen before drawing the popup menu over it. */
2490 update_screen(0);
2491
2492 if (compl_match_array == NULL)
2493 {
2494 /* Need to build the popup menu list. */
2495 compl_match_arraysize = 0;
2496 compl = compl_first_match;
Bram Moolenaara6557602006-02-04 22:43:20 +00002497 if (compl_leader != NULL)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002498 lead_len = (int)STRLEN(compl_leader);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002499 do
2500 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002501 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2502 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002503 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002504 ++compl_match_arraysize;
2505 compl = compl->cp_next;
2506 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaara6557602006-02-04 22:43:20 +00002507 if (compl_match_arraysize == 0)
2508 return;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002509 compl_match_array = (pumitem_T *)alloc_clear(
2510 (unsigned)(sizeof(pumitem_T)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002511 * compl_match_arraysize));
2512 if (compl_match_array != NULL)
2513 {
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002514 /* If the current match is the original text don't find the first
2515 * match after it, don't highlight anything. */
2516 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
2517 shown_match_ok = TRUE;
2518
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002519 i = 0;
2520 compl = compl_first_match;
2521 do
2522 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002523 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2524 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002525 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002526 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002527 if (!shown_match_ok)
2528 {
2529 if (compl == compl_shown_match || did_find_shown_match)
2530 {
2531 /* This item is the shown match or this is the
2532 * first displayed item after the shown match. */
2533 compl_shown_match = compl;
2534 did_find_shown_match = TRUE;
2535 shown_match_ok = TRUE;
2536 }
2537 else
2538 /* Remember this displayed match for when the
2539 * shown match is just below it. */
2540 shown_compl = compl;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002541 cur = i;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002542 }
Bram Moolenaar39f05632006-03-19 22:15:26 +00002543
2544 if (compl->cp_text[CPT_ABBR] != NULL)
2545 compl_match_array[i].pum_text =
2546 compl->cp_text[CPT_ABBR];
2547 else
2548 compl_match_array[i].pum_text = compl->cp_str;
2549 compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
2550 compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
2551 if (compl->cp_text[CPT_MENU] != NULL)
2552 compl_match_array[i++].pum_extra =
2553 compl->cp_text[CPT_MENU];
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002554 else
2555 compl_match_array[i++].pum_extra = compl->cp_fname;
2556 }
2557
2558 if (compl == compl_shown_match)
2559 {
2560 did_find_shown_match = TRUE;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002561
2562 /* When the original text is the shown match don't set
2563 * compl_shown_match. */
2564 if (compl->cp_flags & ORIGINAL_TEXT)
2565 shown_match_ok = TRUE;
2566
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002567 if (!shown_match_ok && shown_compl != NULL)
2568 {
2569 /* The shown match isn't displayed, set it to the
2570 * previously displayed match. */
2571 compl_shown_match = shown_compl;
2572 shown_match_ok = TRUE;
2573 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002574 }
2575 compl = compl->cp_next;
2576 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002577
2578 if (!shown_match_ok) /* no displayed match at all */
2579 cur = -1;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002580 }
2581 }
2582 else
2583 {
2584 /* popup menu already exists, only need to find the current item.*/
Bram Moolenaara6557602006-02-04 22:43:20 +00002585 for (i = 0; i < compl_match_arraysize; ++i)
Bram Moolenaar39f05632006-03-19 22:15:26 +00002586 if (compl_match_array[i].pum_text == compl_shown_match->cp_str
2587 || compl_match_array[i].pum_text
2588 == compl_shown_match->cp_text[CPT_ABBR])
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002589 {
2590 cur = i;
Bram Moolenaara6557602006-02-04 22:43:20 +00002591 break;
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002592 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002593 }
2594
2595 if (compl_match_array != NULL)
2596 {
2597 /* Compute the screen column of the start of the completed text.
2598 * Use the cursor to get all wrapping and other settings right. */
2599 col = curwin->w_cursor.col;
2600 curwin->w_cursor.col = compl_col;
Bram Moolenaard289f132006-03-11 21:30:53 +00002601 pum_display(compl_match_array, compl_match_arraysize, cur);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002602 curwin->w_cursor.col = col;
2603 }
2604}
2605
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606#define DICT_FIRST (1) /* use just first element in "dict" */
2607#define DICT_EXACT (2) /* "dict" is the exact name of a file */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002608
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609/*
Bram Moolenaar0b238792006-03-02 22:49:12 +00002610 * Add any identifiers that match the given pattern in the list of dictionary
2611 * files "dict_start" to the list of completions.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 */
2613 static void
Bram Moolenaar0b238792006-03-02 22:49:12 +00002614ins_compl_dictionaries(dict_start, pat, flags, thesaurus)
2615 char_u *dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 char_u *pat;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002617 int flags; /* DICT_FIRST and/or DICT_EXACT */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002618 int thesaurus; /* Thesaurus completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619{
Bram Moolenaar0b238792006-03-02 22:49:12 +00002620 char_u *dict = dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 char_u *ptr;
2622 char_u *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 regmatch_T regmatch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 char_u **files;
2625 int count;
2626 int i;
2627 int save_p_scs;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002628 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629
Bram Moolenaar0b238792006-03-02 22:49:12 +00002630 if (*dict == NUL)
2631 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002632#ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002633 /* When 'dictionary' is empty and spell checking is enabled use
2634 * "spell". */
2635 if (!thesaurus && curwin->w_p_spell)
2636 dict = (char_u *)"spell";
2637 else
2638#endif
2639 return;
2640 }
2641
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 buf = alloc(LSIZE);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002643 if (buf == NULL)
2644 return;
2645
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 /* If 'infercase' is set, don't use 'smartcase' here */
2647 save_p_scs = p_scs;
2648 if (curbuf->b_p_inf)
2649 p_scs = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002650
2651 /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
2652 * to only match at the start of a line. Otherwise just match the
2653 * pattern. */
2654 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2655 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002656 i = (int)STRLEN(pat) + 8;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002657 ptr = alloc(i);
2658 if (ptr == NULL)
2659 return;
2660 vim_snprintf((char *)ptr, i, "^\\s*\\zs%s", pat);
2661 regmatch.regprog = vim_regcomp(ptr, p_magic ? RE_MAGIC : 0);
2662 vim_free(ptr);
2663 }
2664 else
Bram Moolenaar0b238792006-03-02 22:49:12 +00002665 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002666 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002667 if (regmatch.regprog == NULL)
2668 goto theend;
2669 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002670
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2672 regmatch.rm_ic = ignorecase(pat);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002673 while (*dict != NUL && !got_int && !compl_interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 {
2675 /* copy one dictionary file name into buf */
2676 if (flags == DICT_EXACT)
2677 {
2678 count = 1;
2679 files = &dict;
2680 }
2681 else
2682 {
2683 /* Expand wildcards in the dictionary name, but do not allow
2684 * backticks (for security, the 'dict' option may have been set in
2685 * a modeline). */
2686 copy_option_part(&dict, buf, LSIZE, ",");
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002687# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002688 if (!thesaurus && STRCMP(buf, "spell") == 0)
2689 count = -1;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002690 else
2691# endif
2692 if (vim_strchr(buf, '`') != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 || expand_wildcards(1, &buf, &count, &files,
2694 EW_FILE|EW_SILENT) != OK)
2695 count = 0;
2696 }
2697
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002698# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002699 if (count == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 {
Bram Moolenaar87b5ca52006-03-04 21:55:31 +00002701 /* Complete from active spelling. Skip "\<" in the pattern, we
2702 * don't use it as a RE. */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002703 if (pat[0] == '\\' && pat[1] == '<')
2704 ptr = pat + 2;
2705 else
2706 ptr = pat;
2707 spell_dump_compl(curbuf, ptr, regmatch.rm_ic, &dir, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002709 else
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002710# endif
Bram Moolenaar0b238792006-03-02 22:49:12 +00002711 {
2712 ins_compl_files(count, files, thesaurus, flags,
2713 &regmatch, buf, &dir);
2714 if (flags != DICT_EXACT)
2715 FreeWild(count, files);
2716 }
2717 if (flags != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 break;
2719 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002720
2721theend:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 p_scs = save_p_scs;
2723 vim_free(regmatch.regprog);
2724 vim_free(buf);
2725}
2726
Bram Moolenaar0b238792006-03-02 22:49:12 +00002727 static void
2728ins_compl_files(count, files, thesaurus, flags, regmatch, buf, dir)
2729 int count;
2730 char_u **files;
2731 int thesaurus;
2732 int flags;
2733 regmatch_T *regmatch;
2734 char_u *buf;
2735 int *dir;
2736{
2737 char_u *ptr;
2738 int i;
2739 FILE *fp;
2740 int add_r;
2741
2742 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
2743 {
2744 fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
2745 if (flags != DICT_EXACT)
2746 {
2747 vim_snprintf((char *)IObuff, IOSIZE,
2748 _("Scanning dictionary: %s"), (char *)files[i]);
2749 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2750 }
2751
2752 if (fp != NULL)
2753 {
2754 /*
2755 * Read dictionary file line by line.
2756 * Check each line for a match.
2757 */
2758 while (!got_int && !compl_interrupted
2759 && !vim_fgets(buf, LSIZE, fp))
2760 {
2761 ptr = buf;
2762 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
2763 {
2764 ptr = regmatch->startp[0];
2765 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2766 ptr = find_line_end(ptr);
2767 else
2768 ptr = find_word_end(ptr);
2769 add_r = ins_compl_add_infercase(regmatch->startp[0],
2770 (int)(ptr - regmatch->startp[0]),
Bram Moolenaard289f132006-03-11 21:30:53 +00002771 p_ic, files[i], *dir, 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002772 if (thesaurus)
2773 {
2774 char_u *wstart;
2775
2776 /*
2777 * Add the other matches on the line
2778 */
2779 while (!got_int)
2780 {
2781 /* Find start of the next word. Skip white
2782 * space and punctuation. */
2783 ptr = find_word_start(ptr);
2784 if (*ptr == NUL || *ptr == NL)
2785 break;
2786 wstart = ptr;
2787
2788 /* Find end of the word and add it. */
2789#ifdef FEAT_MBYTE
2790 if (has_mbyte)
2791 /* Japanese words may have characters in
2792 * different classes, only separate words
2793 * with single-byte non-word characters. */
2794 while (*ptr != NUL)
2795 {
2796 int l = (*mb_ptr2len)(ptr);
2797
2798 if (l < 2 && !vim_iswordc(*ptr))
2799 break;
2800 ptr += l;
2801 }
2802 else
2803#endif
2804 ptr = find_word_end(ptr);
2805 add_r = ins_compl_add_infercase(wstart,
2806 (int)(ptr - wstart),
2807 p_ic, files[i], *dir, 0);
2808 }
2809 }
2810 if (add_r == OK)
2811 /* if dir was BACKWARD then honor it just once */
2812 *dir = FORWARD;
2813 else if (add_r == FAIL)
2814 break;
2815 /* avoid expensive call to vim_regexec() when at end
2816 * of line */
2817 if (*ptr == '\n' || got_int)
2818 break;
2819 }
2820 line_breakcheck();
2821 ins_compl_check_keys(50);
2822 }
2823 fclose(fp);
2824 }
2825 }
2826}
2827
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828/*
2829 * Find the start of the next word.
2830 * Returns a pointer to the first char of the word. Also stops at a NUL.
2831 */
2832 char_u *
2833find_word_start(ptr)
2834 char_u *ptr;
2835{
2836#ifdef FEAT_MBYTE
2837 if (has_mbyte)
2838 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002839 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 else
2841#endif
2842 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2843 ++ptr;
2844 return ptr;
2845}
2846
2847/*
2848 * Find the end of the word. Assumes it starts inside a word.
2849 * Returns a pointer to just after the word.
2850 */
2851 char_u *
2852find_word_end(ptr)
2853 char_u *ptr;
2854{
2855#ifdef FEAT_MBYTE
2856 int start_class;
2857
2858 if (has_mbyte)
2859 {
2860 start_class = mb_get_class(ptr);
2861 if (start_class > 1)
2862 while (*ptr != NUL)
2863 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002864 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002865 if (mb_get_class(ptr) != start_class)
2866 break;
2867 }
2868 }
2869 else
2870#endif
2871 while (vim_iswordc(*ptr))
2872 ++ptr;
2873 return ptr;
2874}
2875
2876/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002877 * Find the end of the line, omitting CR and NL at the end.
2878 * Returns a pointer to just after the line.
2879 */
2880 static char_u *
2881find_line_end(ptr)
2882 char_u *ptr;
2883{
2884 char_u *s;
2885
2886 s = ptr + STRLEN(ptr);
2887 while (s > ptr && (s[-1] == CAR || s[-1] == NL))
2888 --s;
2889 return s;
2890}
2891
2892/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 * Free the list of completions
2894 */
2895 static void
2896ins_compl_free()
2897{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002898 compl_T *match;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002899 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002901 vim_free(compl_pattern);
2902 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002903 vim_free(compl_leader);
2904 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002906 if (compl_first_match == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002908
2909 ins_compl_del_pum();
2910 pum_clear();
2911
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002912 compl_curr_match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 do
2914 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002915 match = compl_curr_match;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002916 compl_curr_match = compl_curr_match->cp_next;
2917 vim_free(match->cp_str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 /* several entries may use the same fname, free it just once. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002919 if (match->cp_flags & FREE_FNAME)
2920 vim_free(match->cp_fname);
Bram Moolenaar39f05632006-03-19 22:15:26 +00002921 for (i = 0; i < CPT_COUNT; ++i)
2922 vim_free(match->cp_text[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 vim_free(match);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002924 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
2925 compl_first_match = compl_curr_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926}
2927
2928 static void
2929ins_compl_clear()
2930{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002931 compl_cont_status = 0;
2932 compl_started = FALSE;
2933 compl_matches = 0;
2934 vim_free(compl_pattern);
2935 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002936 vim_free(compl_leader);
2937 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 edit_submode_extra = NULL;
Bram Moolenaara94bc432006-03-10 21:42:59 +00002939 vim_free(compl_orig_text);
2940 compl_orig_text = NULL;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00002941 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942}
2943
2944/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002945 * Return TRUE when Insert completion is active.
2946 */
2947 int
2948ins_compl_active()
2949{
2950 return compl_started;
2951}
2952
2953/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002954 * Delete one character before the cursor and show the subset of the matches
2955 * that match the word that is now before the cursor.
Bram Moolenaarc1e37902006-04-18 21:55:01 +00002956 * Returns the character to be used, NUL if the work is done and another char
2957 * to be got from the user.
Bram Moolenaara6557602006-02-04 22:43:20 +00002958 */
2959 static int
2960ins_compl_bs()
2961{
2962 char_u *line;
2963 char_u *p;
2964
Bram Moolenaarc1e37902006-04-18 21:55:01 +00002965 line = ml_get_curline();
2966 p = line + curwin->w_cursor.col;
2967 mb_ptr_back(line, p);
2968
2969 /* Stop completion when the whole word was deleted. */
2970 if ((int)(p - line) - (int)compl_col <= 0)
2971 return K_BS;
2972
Bram Moolenaara6557602006-02-04 22:43:20 +00002973 if (curwin->w_cursor.col <= compl_col + compl_length)
2974 {
2975 /* Deleted more than what was used to find matches, need to look for
2976 * matches all over again. */
2977 ins_compl_free();
2978 compl_started = FALSE;
2979 compl_matches = 0;
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002980 compl_cont_status = 0;
2981 compl_cont_mode = 0;
Bram Moolenaara6557602006-02-04 22:43:20 +00002982 }
2983
Bram Moolenaara6557602006-02-04 22:43:20 +00002984 vim_free(compl_leader);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002985 compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
Bram Moolenaara6557602006-02-04 22:43:20 +00002986 if (compl_leader != NULL)
2987 {
2988 ins_compl_del_pum();
2989 ins_compl_delete();
2990 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2991
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002992 if (compl_started)
2993 ins_compl_set_original_text(compl_leader);
2994 else
Bram Moolenaara6557602006-02-04 22:43:20 +00002995 {
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00002996#ifdef FEAT_SPELL
2997 spell_bad_len = 0; /* need to redetect bad word */
2998#endif
Bram Moolenaara6557602006-02-04 22:43:20 +00002999 /* Matches were cleared, need to search for them now. */
3000 if (ins_complete(Ctrl_N) == FAIL)
3001 compl_cont_status = 0;
3002 else
3003 {
3004 /* Remove the completed word again. */
3005 ins_compl_delete();
3006 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3007 }
3008 }
3009
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00003010 /* Go to the original text, since none of the matches is inserted. */
3011 if (compl_first_match->cp_prev != NULL
3012 && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT))
3013 compl_shown_match = compl_first_match->cp_prev;
3014 else
3015 compl_shown_match = compl_first_match;
3016 compl_curr_match = compl_shown_match;
3017 compl_shows_dir = compl_direction;
3018
Bram Moolenaara6557602006-02-04 22:43:20 +00003019 /* Show the popup menu with a different set of matches. */
3020 ins_compl_show_pum();
3021 compl_used_match = FALSE;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003022 compl_enter_selects = FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +00003023
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003024 return NUL;
Bram Moolenaara6557602006-02-04 22:43:20 +00003025 }
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003026 return K_BS;
Bram Moolenaara6557602006-02-04 22:43:20 +00003027}
3028
3029/*
3030 * Append one character to the match leader. May reduce the number of
3031 * matches.
3032 */
3033 static void
3034ins_compl_addleader(c)
3035 int c;
3036{
3037#ifdef FEAT_MBYTE
3038 int cc;
3039
3040 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
3041 {
3042 char_u buf[MB_MAXBYTES + 1];
3043
3044 (*mb_char2bytes)(c, buf);
3045 buf[cc] = NUL;
3046 ins_char_bytes(buf, cc);
3047 }
3048 else
3049#endif
3050 ins_char(c);
3051
3052 vim_free(compl_leader);
3053 compl_leader = vim_strnsave(ml_get_curline() + compl_col,
3054 curwin->w_cursor.col - compl_col);
3055 if (compl_leader != NULL)
3056 {
3057 /* Show the popup menu with a different set of matches. */
3058 ins_compl_del_pum();
3059 ins_compl_show_pum();
3060 compl_used_match = FALSE;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003061 compl_enter_selects = FALSE;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003062 ins_compl_set_original_text(compl_leader);
3063 }
3064}
3065
3066/*
3067 * Set the first match, the original text.
3068 */
3069 static void
3070ins_compl_set_original_text(str)
3071 char_u *str;
3072{
3073 char_u *p;
3074
3075 /* Replace the original text entry. */
3076 if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */
3077 {
3078 p = vim_strsave(str);
3079 if (p != NULL)
3080 {
3081 vim_free(compl_first_match->cp_str);
3082 compl_first_match->cp_str = p;
3083 }
Bram Moolenaara6557602006-02-04 22:43:20 +00003084 }
3085}
3086
3087/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003088 * Append one character to the match leader. May reduce the number of
3089 * matches.
3090 */
3091 static void
3092ins_compl_addfrommatch()
3093{
3094 char_u *p;
3095 int len = curwin->w_cursor.col - compl_col;
3096 int c;
3097
3098 p = compl_shown_match->cp_str;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00003099 if ((int)STRLEN(p) <= len) /* the match is too short */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003100 return;
3101 p += len;
3102#ifdef FEAT_MBYTE
3103 c = mb_ptr2char(p);
3104#else
3105 c = *p;
3106#endif
3107 ins_compl_addleader(c);
3108}
3109
3110/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111 * Prepare for Insert mode completion, or stop it.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003112 * Called just after typing a character in Insert mode.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003113 * Returns TRUE when the character is not to be inserted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003115 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116ins_compl_prep(c)
3117 int c;
3118{
3119 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 int temp;
3121 int want_cindent;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003122 int retval = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123
3124 /* Forget any previous 'special' messages if this is actually
3125 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
3126 */
3127 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
3128 edit_submode_extra = NULL;
3129
3130 /* Ignore end of Select mode mapping */
3131 if (c == K_SELECT)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003132 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003134 /* Set "compl_get_longest" when finding the first matches. */
3135 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
3136 || (ctrl_x_mode == 0 && !compl_started))
3137 {
3138 compl_get_longest = (vim_strchr(p_cot, 'l') != NULL);
3139 compl_used_match = TRUE;
3140 }
3141
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
3143 {
3144 /*
3145 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
3146 * it will be yet. Now we decide.
3147 */
3148 switch (c)
3149 {
3150 case Ctrl_E:
3151 case Ctrl_Y:
3152 ctrl_x_mode = CTRL_X_SCROLL;
3153 if (!(State & REPLACE_FLAG))
3154 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
3155 else
3156 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
3157 edit_submode_pre = NULL;
3158 showmode();
3159 break;
3160 case Ctrl_L:
3161 ctrl_x_mode = CTRL_X_WHOLE_LINE;
3162 break;
3163 case Ctrl_F:
3164 ctrl_x_mode = CTRL_X_FILES;
3165 break;
3166 case Ctrl_K:
3167 ctrl_x_mode = CTRL_X_DICTIONARY;
3168 break;
3169 case Ctrl_R:
3170 /* Simply allow ^R to happen without affecting ^X mode */
3171 break;
3172 case Ctrl_T:
3173 ctrl_x_mode = CTRL_X_THESAURUS;
3174 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003175#ifdef FEAT_COMPL_FUNC
3176 case Ctrl_U:
3177 ctrl_x_mode = CTRL_X_FUNCTION;
3178 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003179 case Ctrl_O:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003180 ctrl_x_mode = CTRL_X_OMNI;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003181 break;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003182#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003183 case 's':
3184 case Ctrl_S:
3185 ctrl_x_mode = CTRL_X_SPELL;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003186#ifdef FEAT_SPELL
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003187 ++emsg_off; /* Avoid getting the E756 error twice. */
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003188 spell_back_to_badword();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003189 --emsg_off;
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003190#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003191 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 case Ctrl_RSB:
3193 ctrl_x_mode = CTRL_X_TAGS;
3194 break;
3195#ifdef FEAT_FIND_ID
3196 case Ctrl_I:
3197 case K_S_TAB:
3198 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
3199 break;
3200 case Ctrl_D:
3201 ctrl_x_mode = CTRL_X_PATH_DEFINES;
3202 break;
3203#endif
3204 case Ctrl_V:
3205 case Ctrl_Q:
3206 ctrl_x_mode = CTRL_X_CMDLINE;
3207 break;
3208 case Ctrl_P:
3209 case Ctrl_N:
3210 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
3211 * just started ^X mode, or there were enough ^X's to cancel
3212 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
3213 * do normal expansion when interrupting a different mode (say
3214 * ^X^F^X^P or ^P^X^X^P, see below)
3215 * nothing changes if interrupting mode 0, (eg, the flag
3216 * doesn't change when going to ADDING mode -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003217 if (!(compl_cont_status & CONT_INTRPT))
3218 compl_cont_status |= CONT_LOCAL;
3219 else if (compl_cont_mode != 0)
3220 compl_cont_status &= ~CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 /* FALLTHROUGH */
3222 default:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003223 /* If we have typed at least 2 ^X's... for modes != 0, we set
3224 * compl_cont_status = 0 (eg, as if we had just started ^X
3225 * mode).
3226 * For mode 0, we set "compl_cont_mode" to an impossible
3227 * value, in both cases ^X^X can be used to restart the same
3228 * mode (avoiding ADDING mode).
3229 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
3230 * 'complete' and local ^P expansions respectively.
3231 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
3232 * mode -- Acevedo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 if (c == Ctrl_X)
3234 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003235 if (compl_cont_mode != 0)
3236 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003238 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239 }
3240 ctrl_x_mode = 0;
3241 edit_submode = NULL;
3242 showmode();
3243 break;
3244 }
3245 }
3246 else if (ctrl_x_mode != 0)
3247 {
3248 /* We're already in CTRL-X mode, do we stay in it? */
3249 if (!vim_is_ctrl_x_key(c))
3250 {
3251 if (ctrl_x_mode == CTRL_X_SCROLL)
3252 ctrl_x_mode = 0;
3253 else
3254 ctrl_x_mode = CTRL_X_FINISHED;
3255 edit_submode = NULL;
3256 }
3257 showmode();
3258 }
3259
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003260 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 {
3262 /* Show error message from attempted keyword completion (probably
3263 * 'Pattern not found') until another key is hit, then go back to
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003264 * showing what mode we are in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 showmode();
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003266 if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R
3267 && !ins_compl_pum_key(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 || ctrl_x_mode == CTRL_X_FINISHED)
3269 {
3270 /* Get here when we have finished typing a sequence of ^N and
3271 * ^P or other completion characters in CTRL-X mode. Free up
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003272 * memory that was used, and make sure we can redo the insert. */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003273 if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003275 char_u *p;
3276
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 /*
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003278 * If any of the original typed text has been changed, eg when
3279 * ignorecase is set, we must add back-spaces to the redo
3280 * buffer. We add as few as necessary to delete just the part
3281 * of the original text that has changed.
3282 * When using the longest match, edited the match or used
3283 * CTRL-E then don't use the current match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003285 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
3286 ptr = compl_curr_match->cp_str;
3287 else if (compl_leader != NULL)
3288 ptr = compl_leader;
3289 else
3290 ptr = compl_orig_text;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003291 p = compl_orig_text;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003292 for (temp = 0; p[temp] != NUL && p[temp] == ptr[temp]; ++temp)
3293 ;
3294#ifdef FEAT_MBYTE
3295 if (temp > 0)
3296 temp -= (*mb_head_off)(compl_orig_text, p + temp);
3297#endif
3298 for (p += temp; *p != NUL; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 AppendCharToRedobuff(K_BS);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003300 AppendToRedobuffLit(ptr + temp, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 }
3302
3303#ifdef FEAT_CINDENT
3304 want_cindent = (can_cindent && cindent_on());
3305#endif
3306 /*
3307 * When completing whole lines: fix indent for 'cindent'.
3308 * Otherwise, break line if it's too long.
3309 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003310 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311 {
3312#ifdef FEAT_CINDENT
3313 /* re-indent the current line */
3314 if (want_cindent)
3315 {
3316 do_c_expr_indent();
3317 want_cindent = FALSE; /* don't do it again */
3318 }
3319#endif
3320 }
3321 else
3322 {
3323 /* put the cursor on the last char, for 'tw' formatting */
3324 curwin->w_cursor.col--;
3325 if (stop_arrow() == OK)
3326 insertchar(NUL, 0, -1);
3327 curwin->w_cursor.col++;
3328 }
3329
3330 auto_format(FALSE, TRUE);
3331
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003332 /* If the popup menu is displayed pressing CTRL-Y means accepting
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003333 * the selection without inserting anything. When
3334 * compl_enter_selects is set the Enter key does the same. */
3335 if ((c == Ctrl_Y || (compl_enter_selects
3336 && (c == CAR || c == K_KENTER || c == NL)))
3337 && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003338 retval = TRUE;
3339
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003340 /* CTRL-E means completion is Ended, go back to the typed text. */
3341 if (c == Ctrl_E)
3342 {
3343 ins_compl_delete();
3344 if (compl_leader != NULL)
3345 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3346 else if (compl_first_match != NULL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003347 ins_bytes(compl_orig_text
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003348 + curwin->w_cursor.col - compl_col);
3349 retval = TRUE;
3350 }
3351
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 ins_compl_free();
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003353 compl_started = FALSE;
3354 compl_matches = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 msg_clr_cmdline(); /* necessary for "noshowmode" */
3356 ctrl_x_mode = 0;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003357 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358 if (edit_submode != NULL)
3359 {
3360 edit_submode = NULL;
3361 showmode();
3362 }
3363
3364#ifdef FEAT_CINDENT
3365 /*
3366 * Indent now if a key was typed that is in 'cinkeys'.
3367 */
3368 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
3369 do_c_expr_indent();
3370#endif
3371 }
3372 }
3373
3374 /* reset continue_* if we left expansion-mode, if we stay they'll be
3375 * (re)set properly in ins_complete() */
3376 if (!vim_is_ctrl_x_key(c))
3377 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003378 compl_cont_status = 0;
3379 compl_cont_mode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003381
3382 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383}
3384
3385/*
3386 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
3387 * (depending on flag) starting from buf and looking for a non-scanned
3388 * buffer (other than curbuf). curbuf is special, if it is called with
3389 * buf=curbuf then it has to be the first call for a given flag/expansion.
3390 *
3391 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
3392 */
3393 static buf_T *
3394ins_compl_next_buf(buf, flag)
3395 buf_T *buf;
3396 int flag;
3397{
3398#ifdef FEAT_WINDOWS
3399 static win_T *wp;
3400#endif
3401
3402 if (flag == 'w') /* just windows */
3403 {
3404#ifdef FEAT_WINDOWS
3405 if (buf == curbuf) /* first call for this flag/expansion */
3406 wp = curwin;
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003407 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408 && wp->w_buffer->b_scanned)
3409 ;
3410 buf = wp->w_buffer;
3411#else
3412 buf = curbuf;
3413#endif
3414 }
3415 else
3416 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
3417 * (unlisted buffers)
3418 * When completing whole lines skip unloaded buffers. */
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003419 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 && ((flag == 'U'
3421 ? buf->b_p_bl
3422 : (!buf->b_p_bl
3423 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003424 || buf->b_scanned))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425 ;
3426 return buf;
3427}
3428
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003429#ifdef FEAT_COMPL_FUNC
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003430static void expand_by_function __ARGS((int type, char_u *base));
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003431
3432/*
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003433 * Execute user defined complete function 'completefunc' or 'omnifunc', and
Bram Moolenaare344bea2005-09-01 20:46:49 +00003434 * get matches in "matches".
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003435 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003436 static void
3437expand_by_function(type, base)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003438 int type; /* CTRL_X_OMNI or CTRL_X_FUNCTION */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003439 char_u *base;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003440{
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003441 list_T *matchlist;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003442 char_u *args[2];
Bram Moolenaare344bea2005-09-01 20:46:49 +00003443 char_u *funcname;
3444 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003445
Bram Moolenaare344bea2005-09-01 20:46:49 +00003446 funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
3447 if (*funcname == NUL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003448 return;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003449
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003450 /* Call 'completefunc' to obtain the list of matches. */
3451 args[0] = (char_u *)"0";
Bram Moolenaare344bea2005-09-01 20:46:49 +00003452 args[1] = base;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003453
Bram Moolenaare344bea2005-09-01 20:46:49 +00003454 pos = curwin->w_cursor;
3455 matchlist = call_func_retlist(funcname, 2, args, FALSE);
3456 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003457 if (matchlist == NULL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003458 return;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003459
Bram Moolenaara94bc432006-03-10 21:42:59 +00003460 ins_compl_add_list(matchlist);
3461 list_unref(matchlist);
3462}
3463#endif /* FEAT_COMPL_FUNC */
3464
Bram Moolenaar39f05632006-03-19 22:15:26 +00003465#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00003466/*
3467 * Add completions from a list.
Bram Moolenaara94bc432006-03-10 21:42:59 +00003468 */
3469 static void
3470ins_compl_add_list(list)
3471 list_T *list;
3472{
3473 listitem_T *li;
Bram Moolenaara94bc432006-03-10 21:42:59 +00003474 int dir = compl_direction;
3475
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003476 /* Go through the List with matches and add each of them. */
Bram Moolenaara94bc432006-03-10 21:42:59 +00003477 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003478 {
Bram Moolenaar39f05632006-03-19 22:15:26 +00003479 if (ins_compl_add_tv(&li->li_tv, dir) == OK)
3480 /* if dir was BACKWARD then honor it just once */
3481 dir = FORWARD;
Bram Moolenaar280f1262006-01-30 00:14:18 +00003482 else if (did_emsg)
3483 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003484 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003485}
Bram Moolenaar39f05632006-03-19 22:15:26 +00003486
3487/*
3488 * Add a match to the list of matches from a typeval_T.
3489 * If the given string is already in the list of completions, then return
3490 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
3491 * maybe because alloc() returns NULL, then FAIL is returned.
3492 */
3493 int
3494ins_compl_add_tv(tv, dir)
3495 typval_T *tv;
3496 int dir;
3497{
3498 char_u *word;
3499 int icase = p_ic;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003500 int dup = FALSE;
Bram Moolenaar39f05632006-03-19 22:15:26 +00003501 char_u *(cptext[CPT_COUNT]);
3502
3503 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
3504 {
3505 word = get_dict_string(tv->vval.v_dict, (char_u *)"word", FALSE);
3506 cptext[CPT_ABBR] = get_dict_string(tv->vval.v_dict,
3507 (char_u *)"abbr", FALSE);
3508 cptext[CPT_MENU] = get_dict_string(tv->vval.v_dict,
3509 (char_u *)"menu", FALSE);
3510 cptext[CPT_KIND] = get_dict_string(tv->vval.v_dict,
3511 (char_u *)"kind", FALSE);
3512 cptext[CPT_INFO] = get_dict_string(tv->vval.v_dict,
3513 (char_u *)"info", FALSE);
3514 if (get_dict_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL)
3515 icase = get_dict_number(tv->vval.v_dict, (char_u *)"icase");
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003516 if (get_dict_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
3517 dup = get_dict_number(tv->vval.v_dict, (char_u *)"dup");
Bram Moolenaar39f05632006-03-19 22:15:26 +00003518 }
3519 else
3520 {
3521 word = get_tv_string_chk(tv);
3522 vim_memset(cptext, 0, sizeof(cptext));
3523 }
3524 if (word == NULL || *word == NUL)
3525 return FAIL;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003526 return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, dup);
Bram Moolenaar39f05632006-03-19 22:15:26 +00003527}
Bram Moolenaara94bc432006-03-10 21:42:59 +00003528#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003529
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003530/*
3531 * Get the next expansion(s), using "compl_pattern".
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003532 * The search starts at position "ini" in curbuf and in the direction
3533 * compl_direction.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003534 * When "compl_started" is FALSE start at that position, otherwise continue
3535 * where we stopped searching before.
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003536 * This may return before finding all the matches.
3537 * Return the total number of matches or -1 if still unknown -- Acevedo
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 */
3539 static int
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003540ins_compl_get_exp(ini)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 pos_T *ini;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542{
3543 static pos_T first_match_pos;
3544 static pos_T last_match_pos;
3545 static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003546 static int found_all = FALSE; /* Found all matches of a
3547 certain type. */
3548 static buf_T *ins_buf = NULL; /* buffer being scanned */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549
Bram Moolenaar572cb562005-08-05 21:35:02 +00003550 pos_T *pos;
3551 char_u **matches;
3552 int save_p_scs;
3553 int save_p_ws;
3554 int save_p_ic;
3555 int i;
3556 int num_matches;
3557 int len;
3558 int found_new_match;
3559 int type = ctrl_x_mode;
3560 char_u *ptr;
3561 char_u *dict = NULL;
3562 int dict_f = 0;
3563 compl_T *old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003565 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566 {
3567 for (ins_buf = firstbuf; ins_buf != NULL; ins_buf = ins_buf->b_next)
3568 ins_buf->b_scanned = 0;
3569 found_all = FALSE;
3570 ins_buf = curbuf;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003571 e_cpt = (compl_cont_status & CONT_LOCAL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003572 ? (char_u *)"." : curbuf->b_p_cpt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 last_match_pos = first_match_pos = *ini;
3574 }
3575
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003576 old_match = compl_curr_match; /* remember the last current match */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003577 pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578 /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
3579 for (;;)
3580 {
3581 found_new_match = FAIL;
3582
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003583 /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 * or if found_all says this entry is done. For ^X^L only use the
3585 * entries from 'complete' that look in loaded buffers. */
3586 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003587 && (!compl_started || found_all))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 {
3589 found_all = FALSE;
3590 while (*e_cpt == ',' || *e_cpt == ' ')
3591 e_cpt++;
3592 if (*e_cpt == '.' && !curbuf->b_scanned)
3593 {
3594 ins_buf = curbuf;
3595 first_match_pos = *ini;
3596 /* So that ^N can match word immediately after cursor */
3597 if (ctrl_x_mode == 0)
3598 dec(&first_match_pos);
3599 last_match_pos = first_match_pos;
3600 type = 0;
3601 }
3602 else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
3603 && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
3604 {
3605 /* Scan a buffer, but not the current one. */
3606 if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
3607 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003608 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609 first_match_pos.col = last_match_pos.col = 0;
3610 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
3611 last_match_pos.lnum = 0;
3612 type = 0;
3613 }
3614 else /* unloaded buffer, scan like dictionary */
3615 {
3616 found_all = TRUE;
3617 if (ins_buf->b_fname == NULL)
3618 continue;
3619 type = CTRL_X_DICTIONARY;
3620 dict = ins_buf->b_fname;
3621 dict_f = DICT_EXACT;
3622 }
Bram Moolenaar555b2802005-05-19 21:08:39 +00003623 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624 ins_buf->b_fname == NULL
3625 ? buf_spname(ins_buf)
3626 : ins_buf->b_sfname == NULL
3627 ? (char *)ins_buf->b_fname
3628 : (char *)ins_buf->b_sfname);
3629 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3630 }
3631 else if (*e_cpt == NUL)
3632 break;
3633 else
3634 {
3635 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3636 type = -1;
3637 else if (*e_cpt == 'k' || *e_cpt == 's')
3638 {
3639 if (*e_cpt == 'k')
3640 type = CTRL_X_DICTIONARY;
3641 else
3642 type = CTRL_X_THESAURUS;
3643 if (*++e_cpt != ',' && *e_cpt != NUL)
3644 {
3645 dict = e_cpt;
3646 dict_f = DICT_FIRST;
3647 }
3648 }
3649#ifdef FEAT_FIND_ID
3650 else if (*e_cpt == 'i')
3651 type = CTRL_X_PATH_PATTERNS;
3652 else if (*e_cpt == 'd')
3653 type = CTRL_X_PATH_DEFINES;
3654#endif
3655 else if (*e_cpt == ']' || *e_cpt == 't')
3656 {
3657 type = CTRL_X_TAGS;
3658 sprintf((char*)IObuff, _("Scanning tags."));
3659 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3660 }
3661 else
3662 type = -1;
3663
3664 /* in any case e_cpt is advanced to the next entry */
3665 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
3666
3667 found_all = TRUE;
3668 if (type == -1)
3669 continue;
3670 }
3671 }
3672
3673 switch (type)
3674 {
3675 case -1:
3676 break;
3677#ifdef FEAT_FIND_ID
3678 case CTRL_X_PATH_PATTERNS:
3679 case CTRL_X_PATH_DEFINES:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003680 find_pattern_in_path(compl_pattern, compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003681 (int)STRLEN(compl_pattern), FALSE, FALSE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 (type == CTRL_X_PATH_DEFINES
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003683 && !(compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
3685 (linenr_T)1, (linenr_T)MAXLNUM);
3686 break;
3687#endif
3688
3689 case CTRL_X_DICTIONARY:
3690 case CTRL_X_THESAURUS:
3691 ins_compl_dictionaries(
Bram Moolenaar0b238792006-03-02 22:49:12 +00003692 dict != NULL ? dict
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 : (type == CTRL_X_THESAURUS
3694 ? (*curbuf->b_p_tsr == NUL
3695 ? p_tsr
3696 : curbuf->b_p_tsr)
3697 : (*curbuf->b_p_dict == NUL
3698 ? p_dict
3699 : curbuf->b_p_dict)),
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003700 compl_pattern,
Bram Moolenaar0b238792006-03-02 22:49:12 +00003701 dict != NULL ? dict_f
3702 : 0, type == CTRL_X_THESAURUS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703 dict = NULL;
3704 break;
3705
3706 case CTRL_X_TAGS:
3707 /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
3708 save_p_ic = p_ic;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003709 p_ic = ignorecase(compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710
3711 /* Find up to TAG_MANY matches. Avoids that an enourmous number
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003712 * of matches is found when compl_pattern is empty */
3713 if (find_tags(compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
3715 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
3716 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3717 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003718 ins_compl_add_matches(num_matches, matches, p_ic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 }
3720 p_ic = save_p_ic;
3721 break;
3722
3723 case CTRL_X_FILES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003724 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
3726 {
3727
3728 /* May change home directory back to "~". */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003729 tilde_replace(compl_pattern, num_matches, matches);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003730 ins_compl_add_matches(num_matches, matches,
3731#ifdef CASE_INSENSITIVE_FILENAME
3732 TRUE
3733#else
3734 FALSE
3735#endif
3736 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 }
3738 break;
3739
3740 case CTRL_X_CMDLINE:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003741 if (expand_cmdline(&compl_xp, compl_pattern,
3742 (int)STRLEN(compl_pattern),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 &num_matches, &matches) == EXPAND_OK)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003744 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 break;
3746
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003747#ifdef FEAT_COMPL_FUNC
3748 case CTRL_X_FUNCTION:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003749 case CTRL_X_OMNI:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003750 expand_by_function(type, compl_pattern);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003751 break;
3752#endif
3753
Bram Moolenaar488c6512005-08-11 20:09:58 +00003754 case CTRL_X_SPELL:
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003755#ifdef FEAT_SPELL
Bram Moolenaar488c6512005-08-11 20:09:58 +00003756 num_matches = expand_spelling(first_match_pos.lnum,
3757 first_match_pos.col, compl_pattern, &matches);
3758 if (num_matches > 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003759 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar488c6512005-08-11 20:09:58 +00003760#endif
3761 break;
3762
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763 default: /* normal ^P/^N and ^X^L */
3764 /*
3765 * If 'infercase' is set, don't use 'smartcase' here
3766 */
3767 save_p_scs = p_scs;
3768 if (ins_buf->b_p_inf)
3769 p_scs = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003770
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 /* buffers other than curbuf are scanned from the beginning or the
3772 * end but never from the middle, thus setting nowrapscan in this
3773 * buffers is a good idea, on the other hand, we always set
3774 * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
3775 save_p_ws = p_ws;
3776 if (ins_buf != curbuf)
3777 p_ws = FALSE;
3778 else if (*e_cpt == '.')
3779 p_ws = TRUE;
3780 for (;;)
3781 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003782 int flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003784 /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that
3785 * has added a word that was at the beginning of the line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786 if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003787 || (compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 found_new_match = search_for_exact_line(ins_buf, pos,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003789 compl_direction, compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 else
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003791 found_new_match = searchit(NULL, ins_buf, pos,
3792 compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003793 compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
Bram Moolenaara23ccb82006-02-27 00:08:02 +00003794 RE_LAST, (linenr_T)0);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003795 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003797 /* set "compl_started" even on fail */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003798 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 first_match_pos = *pos;
3800 last_match_pos = *pos;
3801 }
3802 else if (first_match_pos.lnum == last_match_pos.lnum
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003803 && first_match_pos.col == last_match_pos.col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 found_new_match = FAIL;
3805 if (found_new_match == FAIL)
3806 {
3807 if (ins_buf == curbuf)
3808 found_all = TRUE;
3809 break;
3810 }
3811
3812 /* when ADDING, the text before the cursor matches, skip it */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003813 if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 && ini->lnum == pos->lnum
3815 && ini->col == pos->col)
3816 continue;
3817 ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
3818 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3819 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003820 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 {
3822 if (pos->lnum >= ins_buf->b_ml.ml_line_count)
3823 continue;
3824 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3825 if (!p_paste)
3826 ptr = skipwhite(ptr);
3827 }
3828 len = (int)STRLEN(ptr);
3829 }
3830 else
3831 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003832 char_u *tmp_ptr = ptr;
3833
3834 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003836 tmp_ptr += compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 /* Skip if already inside a word. */
3838 if (vim_iswordp(tmp_ptr))
3839 continue;
3840 /* Find start of next word. */
3841 tmp_ptr = find_word_start(tmp_ptr);
3842 }
3843 /* Find end of this word. */
3844 tmp_ptr = find_word_end(tmp_ptr);
3845 len = (int)(tmp_ptr - ptr);
3846
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003847 if ((compl_cont_status & CONT_ADDING)
3848 && len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 {
3850 if (pos->lnum < ins_buf->b_ml.ml_line_count)
3851 {
3852 /* Try next line, if any. the new word will be
3853 * "join" as if the normal command "J" was used.
3854 * IOSIZE is always greater than
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003855 * compl_length, so the next STRNCPY always
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 * works -- Acevedo */
3857 STRNCPY(IObuff, ptr, len);
3858 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3859 tmp_ptr = ptr = skipwhite(ptr);
3860 /* Find start of next word. */
3861 tmp_ptr = find_word_start(tmp_ptr);
3862 /* Find end of next word. */
3863 tmp_ptr = find_word_end(tmp_ptr);
3864 if (tmp_ptr > ptr)
3865 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003866 if (*ptr != ')' && IObuff[len - 1] != TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003868 if (IObuff[len - 1] != ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 IObuff[len++] = ' ';
3870 /* IObuf =~ "\k.* ", thus len >= 2 */
3871 if (p_js
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003872 && (IObuff[len - 2] == '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 || (vim_strchr(p_cpo, CPO_JOINSP)
3874 == NULL
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003875 && (IObuff[len - 2] == '?'
3876 || IObuff[len - 2] == '!'))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 IObuff[len++] = ' ';
3878 }
3879 /* copy as much as posible of the new word */
3880 if (tmp_ptr - ptr >= IOSIZE - len)
3881 tmp_ptr = ptr + IOSIZE - len - 1;
3882 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3883 len += (int)(tmp_ptr - ptr);
Bram Moolenaar572cb562005-08-05 21:35:02 +00003884 flags |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 }
3886 IObuff[len] = NUL;
3887 ptr = IObuff;
3888 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003889 if (len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 continue;
3891 }
3892 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003893 if (ins_compl_add_infercase(ptr, len, p_ic,
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003894 ins_buf == curbuf ? NULL : ins_buf->b_sfname,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003895 0, flags) != NOTDONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 {
3897 found_new_match = OK;
3898 break;
3899 }
3900 }
3901 p_scs = save_p_scs;
3902 p_ws = save_p_ws;
3903 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003904
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003905 /* check if compl_curr_match has changed, (e.g. other type of
3906 * expansion added somenthing) */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003907 if (type != 0 && compl_curr_match != old_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908 found_new_match = OK;
3909
3910 /* break the loop for specialized modes (use 'complete' just for the
3911 * generic ctrl_x_mode == 0) or when we've found a new match */
3912 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003913 || found_new_match != FAIL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003914 {
3915 if (got_int)
3916 break;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003917 /* Fill the popup menu as soon as possible. */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003918 if (pum_wanted() && type != -1)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003919 ins_compl_check_keys(0);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003920
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003921 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
3922 || compl_interrupted)
3923 break;
3924 compl_started = TRUE;
3925 }
3926 else
3927 {
3928 /* Mark a buffer scanned when it has been scanned completely */
3929 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
3930 ins_buf->b_scanned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003931
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003932 compl_started = FALSE;
3933 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003935 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936
3937 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
3938 && *e_cpt == NUL) /* Got to end of 'complete' */
3939 found_new_match = FAIL;
3940
3941 i = -1; /* total of matches, unknown */
3942 if (found_new_match == FAIL
3943 || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
3944 i = ins_compl_make_cyclic();
3945
3946 /* If several matches were added (FORWARD) or the search failed and has
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003947 * just been made cyclic then we have to move compl_curr_match to the next
3948 * or previous entry (if any) -- Acevedo */
Bram Moolenaara94bc432006-03-10 21:42:59 +00003949 compl_curr_match = compl_direction == FORWARD ? old_match->cp_next
3950 : old_match->cp_prev;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003951 if (compl_curr_match == NULL)
3952 compl_curr_match = old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953 return i;
3954}
3955
3956/* Delete the old text being completed. */
3957 static void
3958ins_compl_delete()
3959{
3960 int i;
3961
3962 /*
3963 * In insert mode: Delete the typed part.
3964 * In replace mode: Put the old characters back, if any.
3965 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003966 i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003967 backspace_until_column(i);
3968 changed_cline_bef_curs();
3969}
3970
3971/* Insert the new text being completed. */
3972 static void
3973ins_compl_insert()
3974{
Bram Moolenaar572cb562005-08-05 21:35:02 +00003975 ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00003976 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
3977 compl_used_match = FALSE;
3978 else
3979 compl_used_match = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980}
3981
3982/*
3983 * Fill in the next completion in the current direction.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003984 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
3985 * get more completions. If it is FALSE, then we just do nothing when there
3986 * are no more completions in a given direction. The latter case is used when
3987 * we are still in the middle of finding completions, to allow browsing
3988 * through the ones found so far.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 * Return the total number of matches, or -1 if still unknown -- webb.
3990 *
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003991 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
3992 * compl_shown_match here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 *
3994 * Note that this function may be called recursively once only. First with
Bram Moolenaar572cb562005-08-05 21:35:02 +00003995 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
3996 * calls this function with "allow_get_expansion" FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 */
3998 static int
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003999ins_compl_next(allow_get_expansion, count, insert_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 int allow_get_expansion;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004001 int count; /* repeat completion this many times; should
4002 be at least 1 */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004003 int insert_match; /* Insert the newly selected match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004{
4005 int num_matches = -1;
4006 int i;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004007 int todo = count;
Bram Moolenaara6557602006-02-04 22:43:20 +00004008 compl_T *found_compl = NULL;
4009 int found_end = FALSE;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004010 int advance;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004012 if (compl_leader != NULL
4013 && (compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 {
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004015 /* Set "compl_shown_match" to the actually shown match, it may differ
4016 * when "compl_leader" is used to omit some of the matches. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004017 while (!ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004018 compl_leader, (int)STRLEN(compl_leader))
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004019 && compl_shown_match->cp_next != NULL
4020 && compl_shown_match->cp_next != compl_first_match)
4021 compl_shown_match = compl_shown_match->cp_next;
4022 }
4023
4024 if (allow_get_expansion && insert_match
4025 && (!compl_get_longest || compl_used_match))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026 /* Delete old text to be replaced */
4027 ins_compl_delete();
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004028
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004029 /* When finding the longest common text we stick at the original text,
4030 * don't let CTRL-N or CTRL-P move to the first match. */
4031 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4032
Bram Moolenaare3226be2005-12-18 22:10:00 +00004033 /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4034 * around. */
4035 while (--todo >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004036 {
Bram Moolenaare3226be2005-12-18 22:10:00 +00004037 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004039 if (compl_pending != 0)
4040 --compl_pending;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004041 compl_shown_match = compl_shown_match->cp_next;
Bram Moolenaara6557602006-02-04 22:43:20 +00004042 found_end = (compl_first_match != NULL
4043 && (compl_shown_match->cp_next == compl_first_match
4044 || compl_shown_match == compl_first_match));
Bram Moolenaare3226be2005-12-18 22:10:00 +00004045 }
4046 else if (compl_shows_dir == BACKWARD
4047 && compl_shown_match->cp_prev != NULL)
4048 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004049 if (compl_pending != 0)
4050 ++compl_pending;
Bram Moolenaara6557602006-02-04 22:43:20 +00004051 found_end = (compl_shown_match == compl_first_match);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004052 compl_shown_match = compl_shown_match->cp_prev;
Bram Moolenaara6557602006-02-04 22:43:20 +00004053 found_end |= (compl_shown_match == compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 }
4055 else
Bram Moolenaare3226be2005-12-18 22:10:00 +00004056 {
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004057 if (advance)
4058 {
4059 if (compl_shows_dir == BACKWARD)
4060 --compl_pending;
4061 else
4062 ++compl_pending;
4063 }
Bram Moolenaara6557602006-02-04 22:43:20 +00004064 if (!allow_get_expansion)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004065 return -1;
Bram Moolenaara6557602006-02-04 22:43:20 +00004066
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00004067 num_matches = ins_compl_get_exp(&compl_startpos);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004068 if (compl_pending != 0 && compl_direction == compl_shows_dir
4069 && advance)
Bram Moolenaara6557602006-02-04 22:43:20 +00004070 compl_shown_match = compl_curr_match;
4071 found_end = FALSE;
4072 }
4073 if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
4074 && compl_leader != NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004075 && !ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004076 compl_leader, (int)STRLEN(compl_leader)))
Bram Moolenaara6557602006-02-04 22:43:20 +00004077 ++todo;
4078 else
4079 /* Remember a matching item. */
4080 found_compl = compl_shown_match;
4081
4082 /* Stop at the end of the list when we found a usable match. */
4083 if (found_end)
4084 {
4085 if (found_compl != NULL)
4086 {
4087 compl_shown_match = found_compl;
4088 break;
4089 }
4090 todo = 1; /* use first usable match after wrapping around */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 }
4093
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004094 /* Insert the text of the new completion, or the compl_leader. */
4095 if (insert_match)
4096 {
4097 if (!compl_get_longest || compl_used_match)
4098 ins_compl_insert();
4099 else
4100 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
4101 }
4102 else
4103 compl_used_match = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104
4105 if (!allow_get_expansion)
4106 {
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004107 /* may undisplay the popup menu first */
4108 ins_compl_upd_pum();
4109
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004110 /* redraw to show the user what was inserted */
4111 update_screen(0);
4112
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004113 /* display the updated popup menu */
4114 ins_compl_show_pum();
4115
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 /* Delete old text to be replaced, since we're still searching and
4117 * don't want to match ourselves! */
4118 ins_compl_delete();
4119 }
4120
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004121 /* Enter will select a match when the match wasn't inserted and the popup
4122 * menu is visislbe. */
4123 compl_enter_selects = !insert_match && compl_match_array != NULL;
4124
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125 /*
4126 * Show the file name for the match (if any)
4127 * Truncate the file name to avoid a wait for return.
4128 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004129 if (compl_shown_match->cp_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130 {
4131 STRCPY(IObuff, "match in file ");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004132 i = (vim_strsize(compl_shown_match->cp_fname) + 16) - sc_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 if (i <= 0)
4134 i = 0;
4135 else
4136 STRCAT(IObuff, "<");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004137 STRCAT(IObuff, compl_shown_match->cp_fname + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 msg(IObuff);
4139 redraw_cmdline = FALSE; /* don't overwrite! */
4140 }
4141
4142 return num_matches;
4143}
4144
4145/*
4146 * Call this while finding completions, to check whether the user has hit a key
4147 * that should change the currently displayed completion, or exit completion
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004148 * mode. Also, when compl_pending is not zero, show a completion as soon as
Bram Moolenaar071d4272004-06-13 20:20:40 +00004149 * possible. -- webb
Bram Moolenaar572cb562005-08-05 21:35:02 +00004150 * "frequency" specifies out of how many calls we actually check.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151 */
4152 void
Bram Moolenaar572cb562005-08-05 21:35:02 +00004153ins_compl_check_keys(frequency)
4154 int frequency;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004155{
4156 static int count = 0;
4157
4158 int c;
4159
4160 /* Don't check when reading keys from a script. That would break the test
4161 * scripts */
4162 if (using_script())
4163 return;
4164
4165 /* Only do this at regular intervals */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004166 if (++count < frequency)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 return;
4168 count = 0;
4169
4170 ++no_mapping;
4171 c = vpeekc_any();
4172 --no_mapping;
4173 if (c != NUL)
4174 {
4175 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
4176 {
4177 c = safe_vgetc(); /* Eat the character */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004178 compl_shows_dir = ins_compl_key2dir(c);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004179 (void)ins_compl_next(FALSE, ins_compl_key2count(c),
4180 c != K_UP && c != K_DOWN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 }
4182 else if (c != Ctrl_R)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004183 compl_interrupted = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 }
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004185 if (compl_pending != 0 && !got_int)
4186 (void)ins_compl_next(FALSE, compl_pending > 0
4187 ? compl_pending : -compl_pending, TRUE);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004188}
4189
4190/*
4191 * Decide the direction of Insert mode complete from the key typed.
4192 * Returns BACKWARD or FORWARD.
4193 */
4194 static int
4195ins_compl_key2dir(c)
4196 int c;
4197{
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004198 if (c == Ctrl_P || c == Ctrl_L
4199 || (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP
4200 || c == K_S_UP || c == K_UP)))
Bram Moolenaare3226be2005-12-18 22:10:00 +00004201 return BACKWARD;
4202 return FORWARD;
4203}
4204
4205/*
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004206 * Return TRUE for keys that are used for completion only when the popup menu
4207 * is visible.
4208 */
4209 static int
4210ins_compl_pum_key(c)
4211 int c;
4212{
4213 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004214 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
4215 || c == K_UP || c == K_DOWN);
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004216}
4217
4218/*
Bram Moolenaare3226be2005-12-18 22:10:00 +00004219 * Decide the number of completions to move forward.
4220 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4221 */
4222 static int
4223ins_compl_key2count(c)
4224 int c;
4225{
4226 int h;
4227
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004228 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004229 {
4230 h = pum_get_height();
4231 if (h > 3)
4232 h -= 2; /* keep some context */
4233 return h;
4234 }
4235 return 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236}
4237
4238/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004239 * Return TRUE if completion with "c" should insert the match, FALSE if only
4240 * to change the currently selected completion.
4241 */
4242 static int
4243ins_compl_use_match(c)
4244 int c;
4245{
4246 switch (c)
4247 {
4248 case K_UP:
4249 case K_DOWN:
4250 case K_PAGEDOWN:
4251 case K_KPAGEDOWN:
4252 case K_S_DOWN:
4253 case K_PAGEUP:
4254 case K_KPAGEUP:
4255 case K_S_UP:
4256 return FALSE;
4257 }
4258 return TRUE;
4259}
4260
4261/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 * Do Insert mode completion.
4263 * Called when character "c" was typed, which has a meaning for completion.
4264 * Returns OK if completion was done, FAIL if something failed (out of mem).
4265 */
4266 static int
4267ins_complete(c)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004268 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004270 char_u *line;
4271 int startcol = 0; /* column where searched text starts */
4272 colnr_T curs_col; /* cursor column */
4273 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274
Bram Moolenaare3226be2005-12-18 22:10:00 +00004275 compl_direction = ins_compl_key2dir(c);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004276 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277 {
4278 /* First time we hit ^N or ^P (in a row, I mean) */
4279
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 did_ai = FALSE;
4281#ifdef FEAT_SMARTINDENT
4282 did_si = FALSE;
4283 can_si = FALSE;
4284 can_si_back = FALSE;
4285#endif
4286 if (stop_arrow() == FAIL)
4287 return FAIL;
4288
4289 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004290 curs_col = curwin->w_cursor.col;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004291 compl_pending = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292
4293 /* if this same ctrl_x_mode has been interrupted use the text from
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004294 * "compl_startpos" to the cursor as a pattern to add a new word
4295 * instead of expand the one before the cursor, in word-wise if
4296 * "compl_startpos"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004297 * is not in the same line as the cursor then fix it (the line has
4298 * been split because it was longer than 'tw'). if SOL is set then
4299 * skip the previous pattern, a word at the beginning of the line has
4300 * been inserted, we'll look for that -- Acevedo. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004301 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4302 && compl_cont_mode == ctrl_x_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303 {
4304 /*
4305 * it is a continued search
4306 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004307 compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
4309 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4310 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004311 if (compl_startpos.lnum != curwin->w_cursor.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004313 /* line (probably) wrapped, set compl_startpos to the
4314 * first non_blank in the line, if it is not a wordchar
4315 * include it to get a better pattern, but then we don't
4316 * want the "\\<" prefix, check it bellow */
4317 compl_col = (colnr_T)(skipwhite(line) - line);
4318 compl_startpos.col = compl_col;
4319 compl_startpos.lnum = curwin->w_cursor.lnum;
4320 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 }
4322 else
4323 {
4324 /* S_IPOS was set when we inserted a word that was at the
4325 * beginning of the line, which means that we'll go to SOL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004326 * mode but first we need to redefine compl_startpos */
4327 if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004329 compl_cont_status |= CONT_SOL;
4330 compl_startpos.col = (colnr_T)(skipwhite(
4331 line + compl_length
4332 + compl_startpos.col) - line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004334 compl_col = compl_startpos.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004336 compl_length = curwin->w_cursor.col - (int)compl_col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004337 /* IObuff is used to add a "word from the next line" would we
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 * have enough space? just being paranoic */
4339#define MIN_SPACE 75
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004340 if (compl_length > (IOSIZE - MIN_SPACE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004342 compl_cont_status &= ~CONT_SOL;
4343 compl_length = (IOSIZE - MIN_SPACE);
4344 compl_col = curwin->w_cursor.col - compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004346 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4347 if (compl_length < 1)
4348 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 }
4350 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004351 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004353 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354 }
4355 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004356 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004358 if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004360 compl_cont_mode = ctrl_x_mode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004362 compl_cont_status = 0;
4363 compl_cont_status |= CONT_N_ADDS;
4364 compl_startpos = curwin->w_cursor;
4365 startcol = (int)curs_col;
4366 compl_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 }
4368
4369 /* Work out completion pattern and original text -- webb */
4370 if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
4371 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004372 if ((compl_cont_status & CONT_SOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4374 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004375 if (!(compl_cont_status & CONT_ADDING))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004377 while (--startcol >= 0 && vim_isIDc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004379 compl_col += ++startcol;
4380 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 }
4382 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004383 compl_pattern = str_foldcase(line + compl_col,
4384 compl_length, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004386 compl_pattern = vim_strnsave(line + compl_col,
4387 compl_length);
4388 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 return FAIL;
4390 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004391 else if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392 {
4393 char_u *prefix = (char_u *)"\\<";
4394
4395 /* we need 3 extra chars, 1 for the NUL and
4396 * 2 >= strlen(prefix) -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004397 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4398 compl_length) + 3);
4399 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004401 if (!vim_iswordp(line + compl_col)
4402 || (compl_col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 && (
4404#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004405 vim_iswordp(mb_prevptr(line, line + compl_col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004407 vim_iswordc(line[compl_col - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408#endif
4409 )))
4410 prefix = (char_u *)"";
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004411 STRCPY((char *)compl_pattern, prefix);
4412 (void)quote_meta(compl_pattern + STRLEN(prefix),
4413 line + compl_col, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004415 else if (--startcol < 0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004417 !vim_iswordp(mb_prevptr(line, line + startcol + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004419 !vim_iswordc(line[startcol])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420#endif
4421 )
4422 {
4423 /* Match any word of at least two chars */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004424 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4425 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004427 compl_col += curs_col;
4428 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 }
4430 else
4431 {
4432#ifdef FEAT_MBYTE
4433 /* Search the point of change class of multibyte character
4434 * or not a word single byte character backward. */
4435 if (has_mbyte)
4436 {
4437 int base_class;
4438 int head_off;
4439
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004440 startcol -= (*mb_head_off)(line, line + startcol);
4441 base_class = mb_get_class(line + startcol);
4442 while (--startcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004444 head_off = (*mb_head_off)(line, line + startcol);
4445 if (base_class != mb_get_class(line + startcol
4446 - head_off))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004448 startcol -= head_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 }
4450 }
4451 else
4452#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004453 while (--startcol >= 0 && vim_iswordc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004455 compl_col += ++startcol;
4456 compl_length = (int)curs_col - startcol;
4457 if (compl_length == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458 {
4459 /* Only match word with at least two chars -- webb
4460 * there's no need to call quote_meta,
4461 * alloc(7) is enough -- Acevedo
4462 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004463 compl_pattern = alloc(7);
4464 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004466 STRCPY((char *)compl_pattern, "\\<");
4467 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4468 STRCAT((char *)compl_pattern, "\\k");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469 }
4470 else
4471 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004472 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4473 compl_length) + 3);
4474 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004476 STRCPY((char *)compl_pattern, "\\<");
4477 (void)quote_meta(compl_pattern + 2, line + compl_col,
4478 compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 }
4480 }
4481 }
4482 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4483 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004484 compl_col = (colnr_T)(skipwhite(line) - line);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004485 compl_length = (int)curs_col - (int)compl_col;
4486 if (compl_length < 0) /* cursor in indent: empty pattern */
4487 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004489 compl_pattern = str_foldcase(line + compl_col, compl_length,
4490 NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004492 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4493 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 return FAIL;
4495 }
4496 else if (ctrl_x_mode == CTRL_X_FILES)
4497 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004498 while (--startcol >= 0 && vim_isfilec(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004500 compl_col += ++startcol;
4501 compl_length = (int)curs_col - startcol;
4502 compl_pattern = addstar(line + compl_col, compl_length,
4503 EXPAND_FILES);
4504 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505 return FAIL;
4506 }
4507 else if (ctrl_x_mode == CTRL_X_CMDLINE)
4508 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004509 compl_pattern = vim_strnsave(line, curs_col);
4510 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004512 set_cmd_context(&compl_xp, compl_pattern,
4513 (int)STRLEN(compl_pattern), curs_col);
4514 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4515 || compl_xp.xp_context == EXPAND_NOTHING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004517 startcol = (int)(compl_xp.xp_pattern - compl_pattern);
4518 compl_col = startcol;
4519 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 }
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004521 else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004522 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00004523#ifdef FEAT_COMPL_FUNC
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004524 /*
Bram Moolenaare344bea2005-09-01 20:46:49 +00004525 * Call user defined function 'completefunc' with "a:findstart"
4526 * set to 1 to obtain the length of text to use for completion.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004527 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00004528 char_u *args[2];
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004529 int col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004530 char_u *funcname;
4531 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004532
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004533 /* Call 'completefunc' or 'omnifunc' and get pattern length as a
Bram Moolenaare344bea2005-09-01 20:46:49 +00004534 * string */
4535 funcname = ctrl_x_mode == CTRL_X_FUNCTION
4536 ? curbuf->b_p_cfu : curbuf->b_p_ofu;
4537 if (*funcname == NUL)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004538 {
4539 EMSG2(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
4540 ? "completefunc" : "omnifunc");
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004541 return FAIL;
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004542 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004543
4544 args[0] = (char_u *)"1";
Bram Moolenaare344bea2005-09-01 20:46:49 +00004545 args[1] = NULL;
4546 pos = curwin->w_cursor;
4547 col = call_func_retnr(funcname, 2, args, FALSE);
4548 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004549
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004550 if (col < 0)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004551 col = curs_col;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004552 compl_col = col;
4553 if ((colnr_T)compl_col > curs_col)
4554 compl_col = curs_col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004555
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004556 /* Setup variables for completion. Need to obtain "line" again,
4557 * it may have become invalid. */
4558 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004559 compl_length = curs_col - compl_col;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004560 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4561 if (compl_pattern == NULL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004562#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004563 return FAIL;
4564 }
Bram Moolenaar488c6512005-08-11 20:09:58 +00004565 else if (ctrl_x_mode == CTRL_X_SPELL)
4566 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00004567#ifdef FEAT_SPELL
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +00004568 if (spell_bad_len > 0)
4569 compl_col = curs_col - spell_bad_len;
4570 else
4571 compl_col = spell_word_start(startcol);
4572 if (compl_col >= (colnr_T)startcol)
Bram Moolenaar488c6512005-08-11 20:09:58 +00004573 return FAIL;
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00004574 spell_expand_check_cap(compl_col);
Bram Moolenaare2f98b92006-03-29 21:18:24 +00004575 /* Need to obtain "line" again, it may have become invalid. */
4576 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar488c6512005-08-11 20:09:58 +00004577 compl_length = (int)curs_col - compl_col;
4578 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4579 if (compl_pattern == NULL)
4580#endif
4581 return FAIL;
4582 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004583 else
4584 {
4585 EMSG2(_(e_intern2), "ins_complete()");
4586 return FAIL;
4587 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004589 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 {
4591 edit_submode_pre = (char_u *)_(" Adding");
4592 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4593 {
4594 /* Insert a new line, keep indentation but ignore 'comments' */
4595#ifdef FEAT_COMMENTS
4596 char_u *old = curbuf->b_p_com;
4597
4598 curbuf->b_p_com = (char_u *)"";
4599#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004600 compl_startpos.lnum = curwin->w_cursor.lnum;
4601 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 ins_eol('\r');
4603#ifdef FEAT_COMMENTS
4604 curbuf->b_p_com = old;
4605#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004606 compl_length = 0;
4607 compl_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 }
4609 }
4610 else
4611 {
4612 edit_submode_pre = NULL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004613 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 }
4615
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004616 if (compl_cont_status & CONT_LOCAL)
4617 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 else
4619 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
4620
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00004621 /* Always add completion for the original text. */
4622 vim_free(compl_orig_text);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004623 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
4624 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00004625 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004627 vim_free(compl_pattern);
4628 compl_pattern = NULL;
4629 vim_free(compl_orig_text);
4630 compl_orig_text = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 return FAIL;
4632 }
4633
4634 /* showmode might reset the internal line pointers, so it must
4635 * be called before line = ml_get(), or when this address is no
4636 * longer needed. -- Acevedo.
4637 */
4638 edit_submode_extra = (char_u *)_("-- Searching...");
4639 edit_submode_highl = HLF_COUNT;
4640 showmode();
4641 edit_submode_extra = NULL;
4642 out_flush();
4643 }
4644
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004645 compl_shown_match = compl_curr_match;
4646 compl_shows_dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647
4648 /*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004649 * Find next match (and following matches).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650 */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004651 n = ins_compl_next(TRUE, ins_compl_key2count(c), ins_compl_use_match(c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004653 /* may undisplay the popup menu */
4654 ins_compl_upd_pum();
4655
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004656 if (n > 1) /* all matches have been found */
4657 compl_matches = n;
4658 compl_curr_match = compl_shown_match;
4659 compl_direction = compl_shows_dir;
4660 compl_interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661
4662 /* eat the ESC to avoid leaving insert mode */
4663 if (got_int && !global_busy)
4664 {
4665 (void)vgetc();
4666 got_int = FALSE;
4667 }
4668
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004669 /* we found no match if the list has only the "compl_orig_text"-entry */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004670 if (compl_first_match == compl_first_match->cp_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004672 edit_submode_extra = (compl_cont_status & CONT_ADDING)
4673 && compl_length > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
4675 edit_submode_highl = HLF_E;
4676 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
4677 * because we couldn't expand anything at first place, but if we used
4678 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
4679 * (such as M in M'exico) if not tried already. -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004680 if ( compl_length > 1
4681 || (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 || (ctrl_x_mode != 0
4683 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
4684 && ctrl_x_mode != CTRL_X_PATH_DEFINES))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004685 compl_cont_status &= ~CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 }
4687
Bram Moolenaar572cb562005-08-05 21:35:02 +00004688 if (compl_curr_match->cp_flags & CONT_S_IPOS)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004689 compl_cont_status |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004691 compl_cont_status &= ~CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692
4693 if (edit_submode_extra == NULL)
4694 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004695 if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004696 {
4697 edit_submode_extra = (char_u *)_("Back at original");
4698 edit_submode_highl = HLF_W;
4699 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004700 else if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 {
4702 edit_submode_extra = (char_u *)_("Word from other line");
4703 edit_submode_highl = HLF_COUNT;
4704 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004705 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706 {
4707 edit_submode_extra = (char_u *)_("The only match");
4708 edit_submode_highl = HLF_COUNT;
4709 }
4710 else
4711 {
4712 /* Update completion sequence number when needed. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004713 if (compl_curr_match->cp_number == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004715 int number = 0;
4716 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004718 if (compl_direction == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 {
4720 /* search backwards for the first valid (!= -1) number.
4721 * This should normally succeed already at the first loop
4722 * cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004723 for (match = compl_curr_match->cp_prev; match != NULL
4724 && match != compl_first_match;
4725 match = match->cp_prev)
4726 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004728 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729 break;
4730 }
4731 if (match != NULL)
4732 /* go up and assign all numbers which are not assigned
4733 * yet */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004734 for (match = match->cp_next;
4735 match != NULL && match->cp_number == -1;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004736 match = match->cp_next)
4737 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738 }
4739 else /* BACKWARD */
4740 {
4741 /* search forwards (upwards) for the first valid (!= -1)
4742 * number. This should normally succeed already at the
4743 * first loop cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004744 for (match = compl_curr_match->cp_next; match != NULL
4745 && match != compl_first_match;
4746 match = match->cp_next)
4747 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004749 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 break;
4751 }
4752 if (match != NULL)
4753 /* go down and assign all numbers which are not
4754 * assigned yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004755 for (match = match->cp_prev; match
4756 && match->cp_number == -1;
4757 match = match->cp_prev)
4758 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 }
4760 }
4761
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004762 /* The match should always have a sequence number now, this is
4763 * just a safety check. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004764 if (compl_curr_match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765 {
4766 /* Space for 10 text chars. + 2x10-digit no.s */
4767 static char_u match_ref[31];
4768
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004769 if (compl_matches > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 sprintf((char *)IObuff, _("match %d of %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004771 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004773 sprintf((char *)IObuff, _("match %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004774 compl_curr_match->cp_number);
Bram Moolenaarce0842a2005-07-18 21:58:11 +00004775 vim_strncpy(match_ref, IObuff, 30);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 edit_submode_extra = match_ref;
4777 edit_submode_highl = HLF_R;
4778 if (dollar_vcol)
4779 curs_columns(FALSE);
4780 }
4781 }
4782 }
4783
4784 /* Show a message about what (completion) mode we're in. */
4785 showmode();
4786 if (edit_submode_extra != NULL)
4787 {
4788 if (!p_smd)
4789 msg_attr(edit_submode_extra,
4790 edit_submode_highl < HLF_COUNT
4791 ? hl_attr(edit_submode_highl) : 0);
4792 }
4793 else
4794 msg_clr_cmdline(); /* necessary for "noshowmode" */
4795
Bram Moolenaara94bc432006-03-10 21:42:59 +00004796 /* RedrawingDisabled may be set when invoked through complete(). */
4797 n = RedrawingDisabled;
4798 RedrawingDisabled = 0;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004799 ins_compl_show_pum();
Bram Moolenaara94bc432006-03-10 21:42:59 +00004800 setcursor();
4801 RedrawingDisabled = n;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004802
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 return OK;
4804}
4805
4806/*
4807 * Looks in the first "len" chars. of "src" for search-metachars.
4808 * If dest is not NULL the chars. are copied there quoting (with
4809 * a backslash) the metachars, and dest would be NUL terminated.
4810 * Returns the length (needed) of dest
4811 */
4812 static int
4813quote_meta(dest, src, len)
4814 char_u *dest;
4815 char_u *src;
4816 int len;
4817{
4818 int m;
4819
4820 for (m = len; --len >= 0; src++)
4821 {
4822 switch (*src)
4823 {
4824 case '.':
4825 case '*':
4826 case '[':
4827 if (ctrl_x_mode == CTRL_X_DICTIONARY
4828 || ctrl_x_mode == CTRL_X_THESAURUS)
4829 break;
4830 case '~':
4831 if (!p_magic) /* quote these only if magic is set */
4832 break;
4833 case '\\':
4834 if (ctrl_x_mode == CTRL_X_DICTIONARY
4835 || ctrl_x_mode == CTRL_X_THESAURUS)
4836 break;
4837 case '^': /* currently it's not needed. */
4838 case '$':
4839 m++;
4840 if (dest != NULL)
4841 *dest++ = '\\';
4842 break;
4843 }
4844 if (dest != NULL)
4845 *dest++ = *src;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004846# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004847 /* Copy remaining bytes of a multibyte character. */
4848 if (has_mbyte)
4849 {
4850 int i, mb_len;
4851
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004852 mb_len = (*mb_ptr2len)(src) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 if (mb_len > 0 && len >= mb_len)
4854 for (i = 0; i < mb_len; ++i)
4855 {
4856 --len;
4857 ++src;
4858 if (dest != NULL)
4859 *dest++ = *src;
4860 }
4861 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004862# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 }
4864 if (dest != NULL)
4865 *dest = NUL;
4866
4867 return m;
4868}
4869#endif /* FEAT_INS_EXPAND */
4870
4871/*
4872 * Next character is interpreted literally.
4873 * A one, two or three digit decimal number is interpreted as its byte value.
4874 * If one or two digits are entered, the next character is given to vungetc().
4875 * For Unicode a character > 255 may be returned.
4876 */
4877 int
4878get_literal()
4879{
4880 int cc;
4881 int nc;
4882 int i;
4883 int hex = FALSE;
4884 int octal = FALSE;
4885#ifdef FEAT_MBYTE
4886 int unicode = 0;
4887#endif
4888
4889 if (got_int)
4890 return Ctrl_C;
4891
4892#ifdef FEAT_GUI
4893 /*
4894 * In GUI there is no point inserting the internal code for a special key.
4895 * It is more useful to insert the string "<KEY>" instead. This would
4896 * probably be useful in a text window too, but it would not be
4897 * vi-compatible (maybe there should be an option for it?) -- webb
4898 */
4899 if (gui.in_use)
4900 ++allow_keys;
4901#endif
4902#ifdef USE_ON_FLY_SCROLL
4903 dont_scroll = TRUE; /* disallow scrolling here */
4904#endif
4905 ++no_mapping; /* don't map the next key hits */
4906 cc = 0;
4907 i = 0;
4908 for (;;)
4909 {
4910 do
4911 nc = safe_vgetc();
4912 while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
4913 || nc == K_HOR_SCROLLBAR);
4914#ifdef FEAT_CMDL_INFO
4915 if (!(State & CMDLINE)
4916# ifdef FEAT_MBYTE
4917 && MB_BYTE2LEN_CHECK(nc) == 1
4918# endif
4919 )
4920 add_to_showcmd(nc);
4921#endif
4922 if (nc == 'x' || nc == 'X')
4923 hex = TRUE;
4924 else if (nc == 'o' || nc == 'O')
4925 octal = TRUE;
4926#ifdef FEAT_MBYTE
4927 else if (nc == 'u' || nc == 'U')
4928 unicode = nc;
4929#endif
4930 else
4931 {
4932 if (hex
4933#ifdef FEAT_MBYTE
4934 || unicode != 0
4935#endif
4936 )
4937 {
4938 if (!vim_isxdigit(nc))
4939 break;
4940 cc = cc * 16 + hex2nr(nc);
4941 }
4942 else if (octal)
4943 {
4944 if (nc < '0' || nc > '7')
4945 break;
4946 cc = cc * 8 + nc - '0';
4947 }
4948 else
4949 {
4950 if (!VIM_ISDIGIT(nc))
4951 break;
4952 cc = cc * 10 + nc - '0';
4953 }
4954
4955 ++i;
4956 }
4957
4958 if (cc > 255
4959#ifdef FEAT_MBYTE
4960 && unicode == 0
4961#endif
4962 )
4963 cc = 255; /* limit range to 0-255 */
4964 nc = 0;
4965
4966 if (hex) /* hex: up to two chars */
4967 {
4968 if (i >= 2)
4969 break;
4970 }
4971#ifdef FEAT_MBYTE
4972 else if (unicode) /* Unicode: up to four or eight chars */
4973 {
4974 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
4975 break;
4976 }
4977#endif
4978 else if (i >= 3) /* decimal or octal: up to three chars */
4979 break;
4980 }
4981 if (i == 0) /* no number entered */
4982 {
4983 if (nc == K_ZERO) /* NUL is stored as NL */
4984 {
4985 cc = '\n';
4986 nc = 0;
4987 }
4988 else
4989 {
4990 cc = nc;
4991 nc = 0;
4992 }
4993 }
4994
4995 if (cc == 0) /* NUL is stored as NL */
4996 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00004997#ifdef FEAT_MBYTE
4998 if (enc_dbcs && (cc & 0xff) == 0)
4999 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
5000 second byte will cause trouble! */
5001#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005002
5003 --no_mapping;
5004#ifdef FEAT_GUI
5005 if (gui.in_use)
5006 --allow_keys;
5007#endif
5008 if (nc)
5009 vungetc(nc);
5010 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
5011 return cc;
5012}
5013
5014/*
5015 * Insert character, taking care of special keys and mod_mask
5016 */
5017 static void
5018insert_special(c, allow_modmask, ctrlv)
5019 int c;
5020 int allow_modmask;
5021 int ctrlv; /* c was typed after CTRL-V */
5022{
5023 char_u *p;
5024 int len;
5025
5026 /*
5027 * Special function key, translate into "<Key>". Up to the last '>' is
5028 * inserted with ins_str(), so as not to replace characters in replace
5029 * mode.
5030 * Only use mod_mask for special keys, to avoid things like <S-Space>,
5031 * unless 'allow_modmask' is TRUE.
5032 */
5033#ifdef MACOS
5034 /* Command-key never produces a normal key */
5035 if (mod_mask & MOD_MASK_CMD)
5036 allow_modmask = TRUE;
5037#endif
5038 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
5039 {
5040 p = get_special_key_name(c, mod_mask);
5041 len = (int)STRLEN(p);
5042 c = p[len - 1];
5043 if (len > 2)
5044 {
5045 if (stop_arrow() == FAIL)
5046 return;
5047 p[len - 1] = NUL;
5048 ins_str(p);
Bram Moolenaarebefac62005-12-28 22:39:57 +00005049 AppendToRedobuffLit(p, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005050 ctrlv = FALSE;
5051 }
5052 }
5053 if (stop_arrow() == OK)
5054 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
5055}
5056
5057/*
5058 * Special characters in this context are those that need processing other
5059 * than the simple insertion that can be performed here. This includes ESC
5060 * which terminates the insert, and CR/NL which need special processing to
5061 * open up a new line. This routine tries to optimize insertions performed by
5062 * the "redo", "undo" or "put" commands, so it needs to know when it should
5063 * stop and defer processing to the "normal" mechanism.
5064 * '0' and '^' are special, because they can be followed by CTRL-D.
5065 */
5066#ifdef EBCDIC
5067# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
5068#else
5069# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
5070#endif
5071
5072#ifdef FEAT_MBYTE
5073# define WHITECHAR(cc) (vim_iswhite(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
5074#else
5075# define WHITECHAR(cc) vim_iswhite(cc)
5076#endif
5077
5078 void
5079insertchar(c, flags, second_indent)
5080 int c; /* character to insert or NUL */
5081 int flags; /* INSCHAR_FORMAT, etc. */
5082 int second_indent; /* indent for second line if >= 0 */
5083{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 int textwidth;
5085#ifdef FEAT_COMMENTS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088 int fo_ins_blank;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089
5090 textwidth = comp_textwidth(flags & INSCHAR_FORMAT);
5091 fo_ins_blank = has_format_option(FO_INS_BLANK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092
5093 /*
5094 * Try to break the line in two or more pieces when:
5095 * - Always do this if we have been called to do formatting only.
5096 * - Always do this when 'formatoptions' has the 'a' flag and the line
5097 * ends in white space.
5098 * - Otherwise:
5099 * - Don't do this if inserting a blank
5100 * - Don't do this if an existing character is being replaced, unless
5101 * we're in VREPLACE mode.
5102 * - Do this if the cursor is not on the line where insert started
5103 * or - 'formatoptions' doesn't have 'l' or the line was not too long
5104 * before the insert.
5105 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
5106 * before 'textwidth'
5107 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005108 if (textwidth > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 && ((flags & INSCHAR_FORMAT)
5110 || (!vim_iswhite(c)
5111 && !((State & REPLACE_FLAG)
5112#ifdef FEAT_VREPLACE
5113 && !(State & VREPLACE_FLAG)
5114#endif
5115 && *ml_get_cursor() != NUL)
5116 && (curwin->w_cursor.lnum != Insstart.lnum
5117 || ((!has_format_option(FO_INS_LONG)
5118 || Insstart_textlen <= (colnr_T)textwidth)
5119 && (!fo_ins_blank
5120 || Insstart_blank_vcol <= (colnr_T)textwidth
5121 ))))))
5122 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005123 /* Format with 'formatexpr' when it's set. Use internal formatting
5124 * when 'formatexpr' isn't set or it returns non-zero. */
5125#if defined(FEAT_EVAL)
5126 if (*curbuf->b_p_fex == NUL
5127 || fex_format(curwin->w_cursor.lnum, 1L) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005128#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005129 internal_format(textwidth, second_indent, flags, c == NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005131
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 if (c == NUL) /* only formatting was wanted */
5133 return;
5134
5135#ifdef FEAT_COMMENTS
5136 /* Check whether this character should end a comment. */
5137 if (did_ai && (int)c == end_comment_pending)
5138 {
5139 char_u *line;
5140 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
5141 int middle_len, end_len;
5142 int i;
5143
5144 /*
5145 * Need to remove existing (middle) comment leader and insert end
5146 * comment leader. First, check what comment leader we can find.
5147 */
5148 i = get_leader_len(line = ml_get_curline(), &p, FALSE);
5149 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
5150 {
5151 /* Skip middle-comment string */
5152 while (*p && p[-1] != ':') /* find end of middle flags */
5153 ++p;
5154 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5155 /* Don't count trailing white space for middle_len */
5156 while (middle_len > 0 && vim_iswhite(lead_end[middle_len - 1]))
5157 --middle_len;
5158
5159 /* Find the end-comment string */
5160 while (*p && p[-1] != ':') /* find end of end flags */
5161 ++p;
5162 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5163
5164 /* Skip white space before the cursor */
5165 i = curwin->w_cursor.col;
5166 while (--i >= 0 && vim_iswhite(line[i]))
5167 ;
5168 i++;
5169
5170 /* Skip to before the middle leader */
5171 i -= middle_len;
5172
5173 /* Check some expected things before we go on */
5174 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
5175 {
5176 /* Backspace over all the stuff we want to replace */
5177 backspace_until_column(i);
5178
5179 /*
5180 * Insert the end-comment string, except for the last
5181 * character, which will get inserted as normal later.
5182 */
5183 ins_bytes_len(lead_end, end_len - 1);
5184 }
5185 }
5186 }
5187 end_comment_pending = NUL;
5188#endif
5189
5190 did_ai = FALSE;
5191#ifdef FEAT_SMARTINDENT
5192 did_si = FALSE;
5193 can_si = FALSE;
5194 can_si_back = FALSE;
5195#endif
5196
5197 /*
5198 * If there's any pending input, grab up to INPUT_BUFLEN at once.
5199 * This speeds up normal text input considerably.
5200 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
5201 * need to re-indent at a ':', or any other character (but not what
5202 * 'paste' is set)..
5203 */
5204#ifdef USE_ON_FLY_SCROLL
5205 dont_scroll = FALSE; /* allow scrolling here */
5206#endif
5207
5208 if ( !ISSPECIAL(c)
5209#ifdef FEAT_MBYTE
5210 && (!has_mbyte || (*mb_char2len)(c) == 1)
5211#endif
5212 && vpeekc() != NUL
5213 && !(State & REPLACE_FLAG)
5214#ifdef FEAT_CINDENT
5215 && !cindent_on()
5216#endif
5217#ifdef FEAT_RIGHTLEFT
5218 && !p_ri
5219#endif
5220 )
5221 {
5222#define INPUT_BUFLEN 100
5223 char_u buf[INPUT_BUFLEN + 1];
5224 int i;
5225 colnr_T virtcol = 0;
5226
5227 buf[0] = c;
5228 i = 1;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005229 if (textwidth > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 virtcol = get_nolist_virtcol();
5231 /*
5232 * Stop the string when:
5233 * - no more chars available
5234 * - finding a special character (command key)
5235 * - buffer is full
5236 * - running into the 'textwidth' boundary
5237 * - need to check for abbreviation: A non-word char after a word-char
5238 */
5239 while ( (c = vpeekc()) != NUL
5240 && !ISSPECIAL(c)
5241#ifdef FEAT_MBYTE
5242 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
5243#endif
5244 && i < INPUT_BUFLEN
5245 && (textwidth == 0
5246 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
5247 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
5248 {
5249#ifdef FEAT_RIGHTLEFT
5250 c = vgetc();
5251 if (p_hkmap && KeyTyped)
5252 c = hkmap(c); /* Hebrew mode mapping */
5253# ifdef FEAT_FKMAP
5254 if (p_fkmap && KeyTyped)
5255 c = fkmap(c); /* Farsi mode mapping */
5256# endif
5257 buf[i++] = c;
5258#else
5259 buf[i++] = vgetc();
5260#endif
5261 }
5262
5263#ifdef FEAT_DIGRAPHS
5264 do_digraph(-1); /* clear digraphs */
5265 do_digraph(buf[i-1]); /* may be the start of a digraph */
5266#endif
5267 buf[i] = NUL;
5268 ins_str(buf);
5269 if (flags & INSCHAR_CTRLV)
5270 {
5271 redo_literal(*buf);
5272 i = 1;
5273 }
5274 else
5275 i = 0;
5276 if (buf[i] != NUL)
Bram Moolenaarebefac62005-12-28 22:39:57 +00005277 AppendToRedobuffLit(buf + i, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278 }
5279 else
5280 {
5281#ifdef FEAT_MBYTE
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005282 int cc;
5283
Bram Moolenaar071d4272004-06-13 20:20:40 +00005284 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
5285 {
5286 char_u buf[MB_MAXBYTES + 1];
5287
5288 (*mb_char2bytes)(c, buf);
5289 buf[cc] = NUL;
5290 ins_char_bytes(buf, cc);
5291 AppendCharToRedobuff(c);
5292 }
5293 else
5294#endif
5295 {
5296 ins_char(c);
5297 if (flags & INSCHAR_CTRLV)
5298 redo_literal(c);
5299 else
5300 AppendCharToRedobuff(c);
5301 }
5302 }
5303}
5304
5305/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005306 * Format text at the current insert position.
5307 */
5308 static void
5309internal_format(textwidth, second_indent, flags, format_only)
5310 int textwidth;
5311 int second_indent;
5312 int flags;
5313 int format_only;
5314{
5315 int cc;
5316 int save_char = NUL;
5317 int haveto_redraw = FALSE;
5318 int fo_ins_blank = has_format_option(FO_INS_BLANK);
5319#ifdef FEAT_MBYTE
5320 int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
5321#endif
5322 int fo_white_par = has_format_option(FO_WHITE_PAR);
5323 int first_line = TRUE;
5324#ifdef FEAT_COMMENTS
5325 colnr_T leader_len;
5326 int no_leader = FALSE;
5327 int do_comments = (flags & INSCHAR_DO_COM);
5328#endif
5329
5330 /*
5331 * When 'ai' is off we don't want a space under the cursor to be
5332 * deleted. Replace it with an 'x' temporarily.
5333 */
5334 if (!curbuf->b_p_ai)
5335 {
5336 cc = gchar_cursor();
5337 if (vim_iswhite(cc))
5338 {
5339 save_char = cc;
5340 pchar_cursor('x');
5341 }
5342 }
5343
5344 /*
5345 * Repeat breaking lines, until the current line is not too long.
5346 */
5347 while (!got_int)
5348 {
5349 int startcol; /* Cursor column at entry */
5350 int wantcol; /* column at textwidth border */
5351 int foundcol; /* column for start of spaces */
5352 int end_foundcol = 0; /* column for start of word */
5353 colnr_T len;
5354 colnr_T virtcol;
5355#ifdef FEAT_VREPLACE
5356 int orig_col = 0;
5357 char_u *saved_text = NULL;
5358#endif
5359 colnr_T col;
5360
5361 virtcol = get_nolist_virtcol();
5362 if (virtcol < (colnr_T)textwidth)
5363 break;
5364
5365#ifdef FEAT_COMMENTS
5366 if (no_leader)
5367 do_comments = FALSE;
5368 else if (!(flags & INSCHAR_FORMAT)
5369 && has_format_option(FO_WRAP_COMS))
5370 do_comments = TRUE;
5371
5372 /* Don't break until after the comment leader */
5373 if (do_comments)
5374 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE);
5375 else
5376 leader_len = 0;
5377
5378 /* If the line doesn't start with a comment leader, then don't
5379 * start one in a following broken line. Avoids that a %word
5380 * moved to the start of the next line causes all following lines
5381 * to start with %. */
5382 if (leader_len == 0)
5383 no_leader = TRUE;
5384#endif
5385 if (!(flags & INSCHAR_FORMAT)
5386#ifdef FEAT_COMMENTS
5387 && leader_len == 0
5388#endif
5389 && !has_format_option(FO_WRAP))
5390
5391 {
5392 textwidth = 0;
5393 break;
5394 }
5395 if ((startcol = curwin->w_cursor.col) == 0)
5396 break;
5397
5398 /* find column of textwidth border */
5399 coladvance((colnr_T)textwidth);
5400 wantcol = curwin->w_cursor.col;
5401
5402 curwin->w_cursor.col = startcol - 1;
5403#ifdef FEAT_MBYTE
5404 /* Correct cursor for multi-byte character. */
5405 if (has_mbyte)
5406 mb_adjust_cursor();
5407#endif
5408 foundcol = 0;
5409
5410 /*
5411 * Find position to break at.
5412 * Stop at first entered white when 'formatoptions' has 'v'
5413 */
5414 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
5415 || curwin->w_cursor.lnum != Insstart.lnum
5416 || curwin->w_cursor.col >= Insstart.col)
5417 {
5418 cc = gchar_cursor();
5419 if (WHITECHAR(cc))
5420 {
5421 /* remember position of blank just before text */
5422 end_foundcol = curwin->w_cursor.col;
5423
5424 /* find start of sequence of blanks */
5425 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
5426 {
5427 dec_cursor();
5428 cc = gchar_cursor();
5429 }
5430 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
5431 break; /* only spaces in front of text */
5432#ifdef FEAT_COMMENTS
5433 /* Don't break until after the comment leader */
5434 if (curwin->w_cursor.col < leader_len)
5435 break;
5436#endif
5437 if (has_format_option(FO_ONE_LETTER))
5438 {
5439 /* do not break after one-letter words */
5440 if (curwin->w_cursor.col == 0)
5441 break; /* one-letter word at begin */
5442
5443 col = curwin->w_cursor.col;
5444 dec_cursor();
5445 cc = gchar_cursor();
5446
5447 if (WHITECHAR(cc))
5448 continue; /* one-letter, continue */
5449 curwin->w_cursor.col = col;
5450 }
5451#ifdef FEAT_MBYTE
5452 if (has_mbyte)
5453 foundcol = curwin->w_cursor.col
5454 + (*mb_ptr2len)(ml_get_cursor());
5455 else
5456#endif
5457 foundcol = curwin->w_cursor.col + 1;
5458 if (curwin->w_cursor.col < (colnr_T)wantcol)
5459 break;
5460 }
5461#ifdef FEAT_MBYTE
5462 else if (cc >= 0x100 && fo_multibyte
5463 && curwin->w_cursor.col <= (colnr_T)wantcol)
5464 {
5465 /* Break after or before a multi-byte character. */
5466 foundcol = curwin->w_cursor.col;
5467 if (curwin->w_cursor.col < (colnr_T)wantcol)
5468 foundcol += (*mb_char2len)(cc);
5469 end_foundcol = foundcol;
5470 break;
5471 }
5472#endif
5473 if (curwin->w_cursor.col == 0)
5474 break;
5475 dec_cursor();
5476 }
5477
5478 if (foundcol == 0) /* no spaces, cannot break line */
5479 {
5480 curwin->w_cursor.col = startcol;
5481 break;
5482 }
5483
5484 /* Going to break the line, remove any "$" now. */
5485 undisplay_dollar();
5486
5487 /*
5488 * Offset between cursor position and line break is used by replace
5489 * stack functions. VREPLACE does not use this, and backspaces
5490 * over the text instead.
5491 */
5492#ifdef FEAT_VREPLACE
5493 if (State & VREPLACE_FLAG)
5494 orig_col = startcol; /* Will start backspacing from here */
5495 else
5496#endif
5497 replace_offset = startcol - end_foundcol - 1;
5498
5499 /*
5500 * adjust startcol for spaces that will be deleted and
5501 * characters that will remain on top line
5502 */
5503 curwin->w_cursor.col = foundcol;
5504 while (cc = gchar_cursor(), WHITECHAR(cc))
5505 inc_cursor();
5506 startcol -= curwin->w_cursor.col;
5507 if (startcol < 0)
5508 startcol = 0;
5509
5510#ifdef FEAT_VREPLACE
5511 if (State & VREPLACE_FLAG)
5512 {
5513 /*
5514 * In VREPLACE mode, we will backspace over the text to be
5515 * wrapped, so save a copy now to put on the next line.
5516 */
5517 saved_text = vim_strsave(ml_get_cursor());
5518 curwin->w_cursor.col = orig_col;
5519 if (saved_text == NULL)
5520 break; /* Can't do it, out of memory */
5521 saved_text[startcol] = NUL;
5522
5523 /* Backspace over characters that will move to the next line */
5524 if (!fo_white_par)
5525 backspace_until_column(foundcol);
5526 }
5527 else
5528#endif
5529 {
5530 /* put cursor after pos. to break line */
5531 if (!fo_white_par)
5532 curwin->w_cursor.col = foundcol;
5533 }
5534
5535 /*
5536 * Split the line just before the margin.
5537 * Only insert/delete lines, but don't really redraw the window.
5538 */
5539 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
5540 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
5541#ifdef FEAT_COMMENTS
5542 + (do_comments ? OPENLINE_DO_COM : 0)
5543#endif
5544 , old_indent);
5545 old_indent = 0;
5546
5547 replace_offset = 0;
5548 if (first_line)
5549 {
5550 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
5551 second_indent = get_number_indent(curwin->w_cursor.lnum -1);
5552 if (second_indent >= 0)
5553 {
5554#ifdef FEAT_VREPLACE
5555 if (State & VREPLACE_FLAG)
5556 change_indent(INDENT_SET, second_indent, FALSE, NUL);
5557 else
5558#endif
5559 (void)set_indent(second_indent, SIN_CHANGED);
5560 }
5561 first_line = FALSE;
5562 }
5563
5564#ifdef FEAT_VREPLACE
5565 if (State & VREPLACE_FLAG)
5566 {
5567 /*
5568 * In VREPLACE mode we have backspaced over the text to be
5569 * moved, now we re-insert it into the new line.
5570 */
5571 ins_bytes(saved_text);
5572 vim_free(saved_text);
5573 }
5574 else
5575#endif
5576 {
5577 /*
5578 * Check if cursor is not past the NUL off the line, cindent
5579 * may have added or removed indent.
5580 */
5581 curwin->w_cursor.col += startcol;
5582 len = (colnr_T)STRLEN(ml_get_curline());
5583 if (curwin->w_cursor.col > len)
5584 curwin->w_cursor.col = len;
5585 }
5586
5587 haveto_redraw = TRUE;
5588#ifdef FEAT_CINDENT
5589 can_cindent = TRUE;
5590#endif
5591 /* moved the cursor, don't autoindent or cindent now */
5592 did_ai = FALSE;
5593#ifdef FEAT_SMARTINDENT
5594 did_si = FALSE;
5595 can_si = FALSE;
5596 can_si_back = FALSE;
5597#endif
5598 line_breakcheck();
5599 }
5600
5601 if (save_char != NUL) /* put back space after cursor */
5602 pchar_cursor(save_char);
5603
5604 if (!format_only && haveto_redraw)
5605 {
5606 update_topline();
5607 redraw_curbuf_later(VALID);
5608 }
5609}
5610
5611/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612 * Called after inserting or deleting text: When 'formatoptions' includes the
5613 * 'a' flag format from the current line until the end of the paragraph.
5614 * Keep the cursor at the same position relative to the text.
5615 * The caller must have saved the cursor line for undo, following ones will be
5616 * saved here.
5617 */
5618 void
5619auto_format(trailblank, prev_line)
5620 int trailblank; /* when TRUE also format with trailing blank */
5621 int prev_line; /* may start in previous line */
5622{
5623 pos_T pos;
5624 colnr_T len;
5625 char_u *old;
5626 char_u *new, *pnew;
5627 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005628 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629
5630 if (!has_format_option(FO_AUTO))
5631 return;
5632
5633 pos = curwin->w_cursor;
5634 old = ml_get_curline();
5635
5636 /* may remove added space */
5637 check_auto_format(FALSE);
5638
5639 /* Don't format in Insert mode when the cursor is on a trailing blank, the
5640 * user might insert normal text next. Also skip formatting when "1" is
5641 * in 'formatoptions' and there is a single character before the cursor.
5642 * Otherwise the line would be broken and when typing another non-white
5643 * next they are not joined back together. */
5644 wasatend = (pos.col == STRLEN(old));
5645 if (*old != NUL && !trailblank && wasatend)
5646 {
5647 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005648 cc = gchar_cursor();
5649 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
5650 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005651 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005652 cc = gchar_cursor();
5653 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005654 {
5655 curwin->w_cursor = pos;
5656 return;
5657 }
5658 curwin->w_cursor = pos;
5659 }
5660
5661#ifdef FEAT_COMMENTS
5662 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
5663 * comments. */
5664 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
5665 && get_leader_len(old, NULL, FALSE) == 0)
5666 return;
5667#endif
5668
5669 /*
5670 * May start formatting in a previous line, so that after "x" a word is
5671 * moved to the previous line if it fits there now. Only when this is not
5672 * the start of a paragraph.
5673 */
5674 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
5675 {
5676 --curwin->w_cursor.lnum;
5677 if (u_save_cursor() == FAIL)
5678 return;
5679 }
5680
5681 /*
5682 * Do the formatting and restore the cursor position. "saved_cursor" will
5683 * be adjusted for the text formatting.
5684 */
5685 saved_cursor = pos;
5686 format_lines((linenr_T)-1);
5687 curwin->w_cursor = saved_cursor;
5688 saved_cursor.lnum = 0;
5689
5690 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
5691 {
5692 /* "cannot happen" */
5693 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5694 coladvance((colnr_T)MAXCOL);
5695 }
5696 else
5697 check_cursor_col();
5698
5699 /* Insert mode: If the cursor is now after the end of the line while it
5700 * previously wasn't, the line was broken. Because of the rule above we
5701 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
5702 * formatted. */
5703 if (!wasatend && has_format_option(FO_WHITE_PAR))
5704 {
5705 new = ml_get_curline();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005706 len = (colnr_T)STRLEN(new);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005707 if (curwin->w_cursor.col == len)
5708 {
5709 pnew = vim_strnsave(new, len + 2);
5710 pnew[len] = ' ';
5711 pnew[len + 1] = NUL;
5712 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
5713 /* remove the space later */
5714 did_add_space = TRUE;
5715 }
5716 else
5717 /* may remove added space */
5718 check_auto_format(FALSE);
5719 }
5720
5721 check_cursor();
5722}
5723
5724/*
5725 * When an extra space was added to continue a paragraph for auto-formatting,
5726 * delete it now. The space must be under the cursor, just after the insert
5727 * position.
5728 */
5729 static void
5730check_auto_format(end_insert)
5731 int end_insert; /* TRUE when ending Insert mode */
5732{
5733 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005734 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735
5736 if (did_add_space)
5737 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005738 cc = gchar_cursor();
5739 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740 /* Somehow the space was removed already. */
5741 did_add_space = FALSE;
5742 else
5743 {
5744 if (!end_insert)
5745 {
5746 inc_cursor();
5747 c = gchar_cursor();
5748 dec_cursor();
5749 }
5750 if (c != NUL)
5751 {
5752 /* The space is no longer at the end of the line, delete it. */
5753 del_char(FALSE);
5754 did_add_space = FALSE;
5755 }
5756 }
5757 }
5758}
5759
5760/*
5761 * Find out textwidth to be used for formatting:
5762 * if 'textwidth' option is set, use it
5763 * else if 'wrapmargin' option is set, use W_WIDTH(curwin) - 'wrapmargin'
5764 * if invalid value, use 0.
5765 * Set default to window width (maximum 79) for "gq" operator.
5766 */
5767 int
5768comp_textwidth(ff)
5769 int ff; /* force formatting (for "Q" command) */
5770{
5771 int textwidth;
5772
5773 textwidth = curbuf->b_p_tw;
5774 if (textwidth == 0 && curbuf->b_p_wm)
5775 {
5776 /* The width is the window width minus 'wrapmargin' minus all the
5777 * things that add to the margin. */
5778 textwidth = W_WIDTH(curwin) - curbuf->b_p_wm;
5779#ifdef FEAT_CMDWIN
5780 if (cmdwin_type != 0)
5781 textwidth -= 1;
5782#endif
5783#ifdef FEAT_FOLDING
5784 textwidth -= curwin->w_p_fdc;
5785#endif
5786#ifdef FEAT_SIGNS
5787 if (curwin->w_buffer->b_signlist != NULL
5788# ifdef FEAT_NETBEANS_INTG
5789 || usingNetbeans
5790# endif
5791 )
5792 textwidth -= 1;
5793#endif
5794 if (curwin->w_p_nu)
5795 textwidth -= 8;
5796 }
5797 if (textwidth < 0)
5798 textwidth = 0;
5799 if (ff && textwidth == 0)
5800 {
5801 textwidth = W_WIDTH(curwin) - 1;
5802 if (textwidth > 79)
5803 textwidth = 79;
5804 }
5805 return textwidth;
5806}
5807
5808/*
5809 * Put a character in the redo buffer, for when just after a CTRL-V.
5810 */
5811 static void
5812redo_literal(c)
5813 int c;
5814{
5815 char_u buf[10];
5816
5817 /* Only digits need special treatment. Translate them into a string of
5818 * three digits. */
5819 if (VIM_ISDIGIT(c))
5820 {
5821 sprintf((char *)buf, "%03d", c);
5822 AppendToRedobuff(buf);
5823 }
5824 else
5825 AppendCharToRedobuff(c);
5826}
5827
5828/*
5829 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005830 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005831 */
5832 static void
5833start_arrow(end_insert_pos)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005834 pos_T *end_insert_pos; /* can be NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835{
5836 if (!arrow_used) /* something has been inserted */
5837 {
5838 AppendToRedobuff(ESC_STR);
5839 stop_insert(end_insert_pos, FALSE);
5840 arrow_used = TRUE; /* this means we stopped the current insert */
5841 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005842#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005843 check_spell_redraw();
5844#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845}
5846
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005847#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005848/*
5849 * If we skipped highlighting word at cursor, do it now.
5850 * It may be skipped again, thus reset spell_redraw_lnum first.
5851 */
5852 static void
5853check_spell_redraw()
5854{
5855 if (spell_redraw_lnum != 0)
5856 {
5857 linenr_T lnum = spell_redraw_lnum;
5858
5859 spell_redraw_lnum = 0;
5860 redrawWinline(lnum, FALSE);
5861 }
5862}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005863
5864/*
5865 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
5866 * spelled word, if there is one.
5867 */
5868 static void
5869spell_back_to_badword()
5870{
5871 pos_T tpos = curwin->w_cursor;
5872
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00005873 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005874 if (curwin->w_cursor.col != tpos.col)
5875 start_arrow(&tpos);
5876}
Bram Moolenaar217ad922005-03-20 22:37:15 +00005877#endif
5878
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879/*
5880 * stop_arrow() is called before a change is made in insert mode.
5881 * If an arrow key has been used, start a new insertion.
5882 * Returns FAIL if undo is impossible, shouldn't insert then.
5883 */
5884 int
5885stop_arrow()
5886{
5887 if (arrow_used)
5888 {
5889 if (u_save_cursor() == OK)
5890 {
5891 arrow_used = FALSE;
5892 ins_need_undo = FALSE;
5893 }
5894 Insstart = curwin->w_cursor; /* new insertion starts here */
5895 Insstart_textlen = linetabsize(ml_get_curline());
5896 ai_col = 0;
5897#ifdef FEAT_VREPLACE
5898 if (State & VREPLACE_FLAG)
5899 {
5900 orig_line_count = curbuf->b_ml.ml_line_count;
5901 vr_lines_changed = 1;
5902 }
5903#endif
5904 ResetRedobuff();
5905 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
Bram Moolenaara9b1e742005-12-19 22:14:58 +00005906 new_insert_skip = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907 }
5908 else if (ins_need_undo)
5909 {
5910 if (u_save_cursor() == OK)
5911 ins_need_undo = FALSE;
5912 }
5913
5914#ifdef FEAT_FOLDING
5915 /* Always open fold at the cursor line when inserting something. */
5916 foldOpenCursor();
5917#endif
5918
5919 return (arrow_used || ins_need_undo ? FAIL : OK);
5920}
5921
5922/*
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005923 * Do a few things to stop inserting.
5924 * "end_insert_pos" is where insert ended. It is NULL when we already jumped
5925 * to another window/buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005926 */
5927 static void
5928stop_insert(end_insert_pos, esc)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005929 pos_T *end_insert_pos;
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005930 int esc; /* called by ins_esc() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005931{
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005932 int cc;
5933 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934
5935 stop_redo_ins();
5936 replace_flush(); /* abandon replace stack */
5937
5938 /*
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005939 * Save the inserted text for later redo with ^@ and CTRL-A.
5940 * Don't do it when "restart_edit" was set and nothing was inserted,
5941 * otherwise CTRL-O w and then <Left> will clear "last_insert".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005942 */
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005943 ptr = get_inserted();
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00005944 if (did_restart_edit == 0 || (ptr != NULL
5945 && (int)STRLEN(ptr) > new_insert_skip))
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005946 {
5947 vim_free(last_insert);
5948 last_insert = ptr;
5949 last_insert_skip = new_insert_skip;
5950 }
5951 else
5952 vim_free(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005954 if (!arrow_used && end_insert_pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005955 {
5956 /* Auto-format now. It may seem strange to do this when stopping an
5957 * insertion (or moving the cursor), but it's required when appending
5958 * a line and having it end in a space. But only do it when something
5959 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005960 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005961 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005962 pos_T tpos = curwin->w_cursor;
5963
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964 /* When the cursor is at the end of the line after a space the
5965 * formatting will move it to the following word. Avoid that by
5966 * moving the cursor onto the space. */
5967 cc = 'x';
5968 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
5969 {
5970 dec_cursor();
5971 cc = gchar_cursor();
5972 if (!vim_iswhite(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005973 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974 }
5975
5976 auto_format(TRUE, FALSE);
5977
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005978 if (vim_iswhite(cc))
5979 {
5980 if (gchar_cursor() != NUL)
5981 inc_cursor();
5982#ifdef FEAT_VIRTUALEDIT
5983 /* If the cursor is still at the same character, also keep
5984 * the "coladd". */
5985 if (gchar_cursor() == NUL
5986 && curwin->w_cursor.lnum == tpos.lnum
5987 && curwin->w_cursor.col == tpos.col)
5988 curwin->w_cursor.coladd = tpos.coladd;
5989#endif
5990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991 }
5992
5993 /* If a space was inserted for auto-formatting, remove it now. */
5994 check_auto_format(TRUE);
5995
5996 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005997 * of the line, and put the cursor back.
5998 * Do this when ESC was used or moving the cursor up/down. */
5999 if (did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006000 && curwin->w_cursor.lnum != end_insert_pos->lnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006002 pos_T tpos = curwin->w_cursor;
6003
6004 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar39f05632006-03-19 22:15:26 +00006005 for (;;)
6006 {
6007 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
6008 --curwin->w_cursor.col;
6009 cc = gchar_cursor();
6010 if (!vim_iswhite(cc))
6011 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012 (void)del_char(TRUE);
Bram Moolenaar39f05632006-03-19 22:15:26 +00006013 }
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006014 if (curwin->w_cursor.lnum != tpos.lnum)
6015 curwin->w_cursor = tpos;
6016 else if (cc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017 ++curwin->w_cursor.col; /* put cursor back on the NUL */
6018
6019#ifdef FEAT_VISUAL
6020 /* <C-S-Right> may have started Visual mode, adjust the position for
6021 * deleted characters. */
6022 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
6023 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006024 cc = (int)STRLEN(ml_get_curline());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025 if (VIsual.col > (colnr_T)cc)
6026 {
6027 VIsual.col = cc;
6028# ifdef FEAT_VIRTUALEDIT
6029 VIsual.coladd = 0;
6030# endif
6031 }
6032 }
6033#endif
6034 }
6035 }
6036 did_ai = FALSE;
6037#ifdef FEAT_SMARTINDENT
6038 did_si = FALSE;
6039 can_si = FALSE;
6040 can_si_back = FALSE;
6041#endif
6042
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006043 /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
6044 * now in a different buffer. */
6045 if (end_insert_pos != NULL)
6046 {
6047 curbuf->b_op_start = Insstart;
6048 curbuf->b_op_end = *end_insert_pos;
6049 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050}
6051
6052/*
6053 * Set the last inserted text to a single character.
6054 * Used for the replace command.
6055 */
6056 void
6057set_last_insert(c)
6058 int c;
6059{
6060 char_u *s;
6061
6062 vim_free(last_insert);
6063#ifdef FEAT_MBYTE
6064 last_insert = alloc(MB_MAXBYTES * 3 + 5);
6065#else
6066 last_insert = alloc(6);
6067#endif
6068 if (last_insert != NULL)
6069 {
6070 s = last_insert;
6071 /* Use the CTRL-V only when entering a special char */
6072 if (c < ' ' || c == DEL)
6073 *s++ = Ctrl_V;
6074 s = add_char2buf(c, s);
6075 *s++ = ESC;
6076 *s++ = NUL;
6077 last_insert_skip = 0;
6078 }
6079}
6080
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006081#if defined(EXITFREE) || defined(PROTO)
6082 void
6083free_last_insert()
6084{
6085 vim_free(last_insert);
6086 last_insert = NULL;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006087 vim_free(compl_orig_text);
6088 compl_orig_text = NULL;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006089}
6090#endif
6091
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092/*
6093 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
6094 * and CSI. Handle multi-byte characters.
6095 * Returns a pointer to after the added bytes.
6096 */
6097 char_u *
6098add_char2buf(c, s)
6099 int c;
6100 char_u *s;
6101{
6102#ifdef FEAT_MBYTE
6103 char_u temp[MB_MAXBYTES];
6104 int i;
6105 int len;
6106
6107 len = (*mb_char2bytes)(c, temp);
6108 for (i = 0; i < len; ++i)
6109 {
6110 c = temp[i];
6111#endif
6112 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
6113 if (c == K_SPECIAL)
6114 {
6115 *s++ = K_SPECIAL;
6116 *s++ = KS_SPECIAL;
6117 *s++ = KE_FILLER;
6118 }
6119#ifdef FEAT_GUI
6120 else if (c == CSI)
6121 {
6122 *s++ = CSI;
6123 *s++ = KS_EXTRA;
6124 *s++ = (int)KE_CSI;
6125 }
6126#endif
6127 else
6128 *s++ = c;
6129#ifdef FEAT_MBYTE
6130 }
6131#endif
6132 return s;
6133}
6134
6135/*
6136 * move cursor to start of line
6137 * if flags & BL_WHITE move to first non-white
6138 * if flags & BL_SOL move to first non-white if startofline is set,
6139 * otherwise keep "curswant" column
6140 * if flags & BL_FIX don't leave the cursor on a NUL.
6141 */
6142 void
6143beginline(flags)
6144 int flags;
6145{
6146 if ((flags & BL_SOL) && !p_sol)
6147 coladvance(curwin->w_curswant);
6148 else
6149 {
6150 curwin->w_cursor.col = 0;
6151#ifdef FEAT_VIRTUALEDIT
6152 curwin->w_cursor.coladd = 0;
6153#endif
6154
6155 if (flags & (BL_WHITE | BL_SOL))
6156 {
6157 char_u *ptr;
6158
6159 for (ptr = ml_get_curline(); vim_iswhite(*ptr)
6160 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
6161 ++curwin->w_cursor.col;
6162 }
6163 curwin->w_set_curswant = TRUE;
6164 }
6165}
6166
6167/*
6168 * oneright oneleft cursor_down cursor_up
6169 *
6170 * Move one char {right,left,down,up}.
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006171 * Doesn't move onto the NUL past the end of the line, unless it is allowed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006172 * Return OK when successful, FAIL when we hit a line of file boundary.
6173 */
6174
6175 int
6176oneright()
6177{
6178 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180
6181#ifdef FEAT_VIRTUALEDIT
6182 if (virtual_active())
6183 {
6184 pos_T prevpos = curwin->w_cursor;
6185
6186 /* Adjust for multi-wide char (excluding TAB) */
6187 ptr = ml_get_cursor();
6188 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006189# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00006190 (*mb_ptr2char)(ptr)
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006191# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192 *ptr
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006193# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194 ))
6195 ? ptr2cells(ptr) : 1));
6196 curwin->w_set_curswant = TRUE;
6197 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
6198 return (prevpos.col != curwin->w_cursor.col
6199 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
6200 }
6201#endif
6202
6203 ptr = ml_get_cursor();
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006204 if (*ptr == NUL)
6205 return FAIL; /* already at the very end */
6206
Bram Moolenaar071d4272004-06-13 20:20:40 +00006207#ifdef FEAT_MBYTE
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006208 if (has_mbyte)
6209 l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006210 else
6211#endif
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006212 l = 1;
6213
6214 /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
6215 * contains "onemore". */
6216 if (ptr[l] == NUL
6217#ifdef FEAT_VIRTUALEDIT
6218 && (ve_flags & VE_ONEMORE) == 0
6219#endif
6220 )
6221 return FAIL;
6222 curwin->w_cursor.col += l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223
6224 curwin->w_set_curswant = TRUE;
6225 return OK;
6226}
6227
6228 int
6229oneleft()
6230{
6231#ifdef FEAT_VIRTUALEDIT
6232 if (virtual_active())
6233 {
6234 int width;
6235 int v = getviscol();
6236
6237 if (v == 0)
6238 return FAIL;
6239
6240# ifdef FEAT_LINEBREAK
6241 /* We might get stuck on 'showbreak', skip over it. */
6242 width = 1;
6243 for (;;)
6244 {
6245 coladvance(v - width);
6246 /* getviscol() is slow, skip it when 'showbreak' is empty and
6247 * there are no multi-byte characters */
6248 if ((*p_sbr == NUL
6249# ifdef FEAT_MBYTE
6250 && !has_mbyte
6251# endif
6252 ) || getviscol() < v)
6253 break;
6254 ++width;
6255 }
6256# else
6257 coladvance(v - 1);
6258# endif
6259
6260 if (curwin->w_cursor.coladd == 1)
6261 {
6262 char_u *ptr;
6263
6264 /* Adjust for multi-wide char (not a TAB) */
6265 ptr = ml_get_cursor();
6266 if (*ptr != TAB && vim_isprintc(
6267# ifdef FEAT_MBYTE
6268 (*mb_ptr2char)(ptr)
6269# else
6270 *ptr
6271# endif
6272 ) && ptr2cells(ptr) > 1)
6273 curwin->w_cursor.coladd = 0;
6274 }
6275
6276 curwin->w_set_curswant = TRUE;
6277 return OK;
6278 }
6279#endif
6280
6281 if (curwin->w_cursor.col == 0)
6282 return FAIL;
6283
6284 curwin->w_set_curswant = TRUE;
6285 --curwin->w_cursor.col;
6286
6287#ifdef FEAT_MBYTE
6288 /* if the character on the left of the current cursor is a multi-byte
6289 * character, move to its first byte */
6290 if (has_mbyte)
6291 mb_adjust_cursor();
6292#endif
6293 return OK;
6294}
6295
6296 int
6297cursor_up(n, upd_topline)
6298 long n;
6299 int upd_topline; /* When TRUE: update topline */
6300{
6301 linenr_T lnum;
6302
6303 if (n > 0)
6304 {
6305 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00006306 /* This fails if the cursor is already in the first line or the count
6307 * is larger than the line number and '-' is in 'cpoptions' */
6308 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309 return FAIL;
6310 if (n >= lnum)
6311 lnum = 1;
6312 else
6313#ifdef FEAT_FOLDING
6314 if (hasAnyFolding(curwin))
6315 {
6316 /*
6317 * Count each sequence of folded lines as one logical line.
6318 */
6319 /* go to the the start of the current fold */
6320 (void)hasFolding(lnum, &lnum, NULL);
6321
6322 while (n--)
6323 {
6324 /* move up one line */
6325 --lnum;
6326 if (lnum <= 1)
6327 break;
6328 /* If we entered a fold, move to the beginning, unless in
6329 * Insert mode or when 'foldopen' contains "all": it will open
6330 * in a moment. */
6331 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
6332 (void)hasFolding(lnum, &lnum, NULL);
6333 }
6334 if (lnum < 1)
6335 lnum = 1;
6336 }
6337 else
6338#endif
6339 lnum -= n;
6340 curwin->w_cursor.lnum = lnum;
6341 }
6342
6343 /* try to advance to the column we want to be at */
6344 coladvance(curwin->w_curswant);
6345
6346 if (upd_topline)
6347 update_topline(); /* make sure curwin->w_topline is valid */
6348
6349 return OK;
6350}
6351
6352/*
6353 * Cursor down a number of logical lines.
6354 */
6355 int
6356cursor_down(n, upd_topline)
6357 long n;
6358 int upd_topline; /* When TRUE: update topline */
6359{
6360 linenr_T lnum;
6361
6362 if (n > 0)
6363 {
6364 lnum = curwin->w_cursor.lnum;
6365#ifdef FEAT_FOLDING
6366 /* Move to last line of fold, will fail if it's the end-of-file. */
6367 (void)hasFolding(lnum, NULL, &lnum);
6368#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00006369 /* This fails if the cursor is already in the last line or would move
6370 * beyound the last line and '-' is in 'cpoptions' */
6371 if (lnum >= curbuf->b_ml.ml_line_count
6372 || (lnum + n > curbuf->b_ml.ml_line_count
6373 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006374 return FAIL;
6375 if (lnum + n >= curbuf->b_ml.ml_line_count)
6376 lnum = curbuf->b_ml.ml_line_count;
6377 else
6378#ifdef FEAT_FOLDING
6379 if (hasAnyFolding(curwin))
6380 {
6381 linenr_T last;
6382
6383 /* count each sequence of folded lines as one logical line */
6384 while (n--)
6385 {
6386 if (hasFolding(lnum, NULL, &last))
6387 lnum = last + 1;
6388 else
6389 ++lnum;
6390 if (lnum >= curbuf->b_ml.ml_line_count)
6391 break;
6392 }
6393 if (lnum > curbuf->b_ml.ml_line_count)
6394 lnum = curbuf->b_ml.ml_line_count;
6395 }
6396 else
6397#endif
6398 lnum += n;
6399 curwin->w_cursor.lnum = lnum;
6400 }
6401
6402 /* try to advance to the column we want to be at */
6403 coladvance(curwin->w_curswant);
6404
6405 if (upd_topline)
6406 update_topline(); /* make sure curwin->w_topline is valid */
6407
6408 return OK;
6409}
6410
6411/*
6412 * Stuff the last inserted text in the read buffer.
6413 * Last_insert actually is a copy of the redo buffer, so we
6414 * first have to remove the command.
6415 */
6416 int
6417stuff_inserted(c, count, no_esc)
6418 int c; /* Command character to be inserted */
6419 long count; /* Repeat this many times */
6420 int no_esc; /* Don't add an ESC at the end */
6421{
6422 char_u *esc_ptr;
6423 char_u *ptr;
6424 char_u *last_ptr;
6425 char_u last = NUL;
6426
6427 ptr = get_last_insert();
6428 if (ptr == NULL)
6429 {
6430 EMSG(_(e_noinstext));
6431 return FAIL;
6432 }
6433
6434 /* may want to stuff the command character, to start Insert mode */
6435 if (c != NUL)
6436 stuffcharReadbuff(c);
6437 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
6438 *esc_ptr = NUL; /* remove the ESC */
6439
6440 /* when the last char is either "0" or "^" it will be quoted if no ESC
6441 * comes after it OR if it will inserted more than once and "ptr"
6442 * starts with ^D. -- Acevedo
6443 */
6444 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
6445 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
6446 && (no_esc || (*ptr == Ctrl_D && count > 1)))
6447 {
6448 last = *last_ptr;
6449 *last_ptr = NUL;
6450 }
6451
6452 do
6453 {
6454 stuffReadbuff(ptr);
6455 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
6456 if (last)
6457 stuffReadbuff((char_u *)(last == '0'
6458 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
6459 : IF_EB("\026^", CTRL_V_STR "^")));
6460 }
6461 while (--count > 0);
6462
6463 if (last)
6464 *last_ptr = last;
6465
6466 if (esc_ptr != NULL)
6467 *esc_ptr = ESC; /* put the ESC back */
6468
6469 /* may want to stuff a trailing ESC, to get out of Insert mode */
6470 if (!no_esc)
6471 stuffcharReadbuff(ESC);
6472
6473 return OK;
6474}
6475
6476 char_u *
6477get_last_insert()
6478{
6479 if (last_insert == NULL)
6480 return NULL;
6481 return last_insert + last_insert_skip;
6482}
6483
6484/*
6485 * Get last inserted string, and remove trailing <Esc>.
6486 * Returns pointer to allocated memory (must be freed) or NULL.
6487 */
6488 char_u *
6489get_last_insert_save()
6490{
6491 char_u *s;
6492 int len;
6493
6494 if (last_insert == NULL)
6495 return NULL;
6496 s = vim_strsave(last_insert + last_insert_skip);
6497 if (s != NULL)
6498 {
6499 len = (int)STRLEN(s);
6500 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
6501 s[len - 1] = NUL;
6502 }
6503 return s;
6504}
6505
6506/*
6507 * Check the word in front of the cursor for an abbreviation.
6508 * Called when the non-id character "c" has been entered.
6509 * When an abbreviation is recognized it is removed from the text and
6510 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
6511 */
6512 static int
6513echeck_abbr(c)
6514 int c;
6515{
6516 /* Don't check for abbreviation in paste mode, when disabled and just
6517 * after moving around with cursor keys. */
6518 if (p_paste || no_abbr || arrow_used)
6519 return FALSE;
6520
6521 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
6522 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
6523}
6524
6525/*
6526 * replace-stack functions
6527 *
6528 * When replacing characters, the replaced characters are remembered for each
6529 * new character. This is used to re-insert the old text when backspacing.
6530 *
6531 * There is a NUL headed list of characters for each character that is
6532 * currently in the file after the insertion point. When BS is used, one NUL
6533 * headed list is put back for the deleted character.
6534 *
6535 * For a newline, there are two NUL headed lists. One contains the characters
6536 * that the NL replaced. The extra one stores the characters after the cursor
6537 * that were deleted (always white space).
6538 *
6539 * Replace_offset is normally 0, in which case replace_push will add a new
6540 * character at the end of the stack. If replace_offset is not 0, that many
6541 * characters will be left on the stack above the newly inserted character.
6542 */
6543
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00006544static char_u *replace_stack = NULL;
6545static long replace_stack_nr = 0; /* next entry in replace stack */
6546static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006547
6548 void
6549replace_push(c)
6550 int c; /* character that is replaced (NUL is none) */
6551{
6552 char_u *p;
6553
6554 if (replace_stack_nr < replace_offset) /* nothing to do */
6555 return;
6556 if (replace_stack_len <= replace_stack_nr)
6557 {
6558 replace_stack_len += 50;
6559 p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
6560 if (p == NULL) /* out of memory */
6561 {
6562 replace_stack_len -= 50;
6563 return;
6564 }
6565 if (replace_stack != NULL)
6566 {
6567 mch_memmove(p, replace_stack,
6568 (size_t)(replace_stack_nr * sizeof(char_u)));
6569 vim_free(replace_stack);
6570 }
6571 replace_stack = p;
6572 }
6573 p = replace_stack + replace_stack_nr - replace_offset;
6574 if (replace_offset)
6575 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
6576 *p = c;
6577 ++replace_stack_nr;
6578}
6579
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006580#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006581/*
6582 * call replace_push(c) with replace_offset set to the first NUL.
6583 */
6584 static void
6585replace_push_off(c)
6586 int c;
6587{
6588 char_u *p;
6589
6590 p = replace_stack + replace_stack_nr;
6591 for (replace_offset = 1; replace_offset < replace_stack_nr;
6592 ++replace_offset)
6593 if (*--p == NUL)
6594 break;
6595 replace_push(c);
6596 replace_offset = 0;
6597}
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006598#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599
6600/*
6601 * Pop one item from the replace stack.
6602 * return -1 if stack empty
6603 * return replaced character or NUL otherwise
6604 */
6605 static int
6606replace_pop()
6607{
6608 if (replace_stack_nr == 0)
6609 return -1;
6610 return (int)replace_stack[--replace_stack_nr];
6611}
6612
6613/*
6614 * Join the top two items on the replace stack. This removes to "off"'th NUL
6615 * encountered.
6616 */
6617 static void
6618replace_join(off)
6619 int off; /* offset for which NUL to remove */
6620{
6621 int i;
6622
6623 for (i = replace_stack_nr; --i >= 0; )
6624 if (replace_stack[i] == NUL && off-- <= 0)
6625 {
6626 --replace_stack_nr;
6627 mch_memmove(replace_stack + i, replace_stack + i + 1,
6628 (size_t)(replace_stack_nr - i));
6629 return;
6630 }
6631}
6632
6633/*
6634 * Pop bytes from the replace stack until a NUL is found, and insert them
6635 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
6636 */
6637 static void
6638replace_pop_ins()
6639{
6640 int cc;
6641 int oldState = State;
6642
6643 State = NORMAL; /* don't want REPLACE here */
6644 while ((cc = replace_pop()) > 0)
6645 {
6646#ifdef FEAT_MBYTE
6647 mb_replace_pop_ins(cc);
6648#else
6649 ins_char(cc);
6650#endif
6651 dec_cursor();
6652 }
6653 State = oldState;
6654}
6655
6656#ifdef FEAT_MBYTE
6657/*
6658 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
6659 * indicates a multi-byte char, pop the other bytes too.
6660 */
6661 static void
6662mb_replace_pop_ins(cc)
6663 int cc;
6664{
6665 int n;
6666 char_u buf[MB_MAXBYTES];
6667 int i;
6668 int c;
6669
6670 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
6671 {
6672 buf[0] = cc;
6673 for (i = 1; i < n; ++i)
6674 buf[i] = replace_pop();
6675 ins_bytes_len(buf, n);
6676 }
6677 else
6678 ins_char(cc);
6679
6680 if (enc_utf8)
6681 /* Handle composing chars. */
6682 for (;;)
6683 {
6684 c = replace_pop();
6685 if (c == -1) /* stack empty */
6686 break;
6687 if ((n = MB_BYTE2LEN(c)) == 1)
6688 {
6689 /* Not a multi-byte char, put it back. */
6690 replace_push(c);
6691 break;
6692 }
6693 else
6694 {
6695 buf[0] = c;
6696 for (i = 1; i < n; ++i)
6697 buf[i] = replace_pop();
6698 if (utf_iscomposing(utf_ptr2char(buf)))
6699 ins_bytes_len(buf, n);
6700 else
6701 {
6702 /* Not a composing char, put it back. */
6703 for (i = n - 1; i >= 0; --i)
6704 replace_push(buf[i]);
6705 break;
6706 }
6707 }
6708 }
6709}
6710#endif
6711
6712/*
6713 * make the replace stack empty
6714 * (called when exiting replace mode)
6715 */
6716 static void
6717replace_flush()
6718{
6719 vim_free(replace_stack);
6720 replace_stack = NULL;
6721 replace_stack_len = 0;
6722 replace_stack_nr = 0;
6723}
6724
6725/*
6726 * Handle doing a BS for one character.
6727 * cc < 0: replace stack empty, just move cursor
6728 * cc == 0: character was inserted, delete it
6729 * cc > 0: character was replaced, put cc (first byte of original char) back
6730 * and check for more characters to be put back
6731 */
6732 static void
6733replace_do_bs()
6734{
6735 int cc;
6736#ifdef FEAT_VREPLACE
6737 int orig_len = 0;
6738 int ins_len;
6739 int orig_vcols = 0;
6740 colnr_T start_vcol;
6741 char_u *p;
6742 int i;
6743 int vcol;
6744#endif
6745
6746 cc = replace_pop();
6747 if (cc > 0)
6748 {
6749#ifdef FEAT_VREPLACE
6750 if (State & VREPLACE_FLAG)
6751 {
6752 /* Get the number of screen cells used by the character we are
6753 * going to delete. */
6754 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
6755 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
6756 }
6757#endif
6758#ifdef FEAT_MBYTE
6759 if (has_mbyte)
6760 {
6761 del_char(FALSE);
6762# ifdef FEAT_VREPLACE
6763 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006764 orig_len = (int)STRLEN(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006765# endif
6766 replace_push(cc);
6767 }
6768 else
6769#endif
6770 {
6771 pchar_cursor(cc);
6772#ifdef FEAT_VREPLACE
6773 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006774 orig_len = (int)STRLEN(ml_get_cursor()) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006775#endif
6776 }
6777 replace_pop_ins();
6778
6779#ifdef FEAT_VREPLACE
6780 if (State & VREPLACE_FLAG)
6781 {
6782 /* Get the number of screen cells used by the inserted characters */
6783 p = ml_get_cursor();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006784 ins_len = (int)STRLEN(p) - orig_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785 vcol = start_vcol;
6786 for (i = 0; i < ins_len; ++i)
6787 {
6788 vcol += chartabsize(p + i, vcol);
6789#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006790 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006791#endif
6792 }
6793 vcol -= start_vcol;
6794
6795 /* Delete spaces that were inserted after the cursor to keep the
6796 * text aligned. */
6797 curwin->w_cursor.col += ins_len;
6798 while (vcol > orig_vcols && gchar_cursor() == ' ')
6799 {
6800 del_char(FALSE);
6801 ++orig_vcols;
6802 }
6803 curwin->w_cursor.col -= ins_len;
6804 }
6805#endif
6806
6807 /* mark the buffer as changed and prepare for displaying */
6808 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
6809 }
6810 else if (cc == 0)
6811 (void)del_char(FALSE);
6812}
6813
6814#ifdef FEAT_CINDENT
6815/*
6816 * Return TRUE if C-indenting is on.
6817 */
6818 static int
6819cindent_on()
6820{
6821 return (!p_paste && (curbuf->b_p_cin
6822# ifdef FEAT_EVAL
6823 || *curbuf->b_p_inde != NUL
6824# endif
6825 ));
6826}
6827#endif
6828
6829#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
6830/*
6831 * Re-indent the current line, based on the current contents of it and the
6832 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
6833 * confused what all the part that handles Control-T is doing that I'm not.
6834 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
6835 */
6836
6837 void
6838fixthisline(get_the_indent)
6839 int (*get_the_indent) __ARGS((void));
6840{
6841 change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
6842 if (linewhite(curwin->w_cursor.lnum))
6843 did_ai = TRUE; /* delete the indent if the line stays empty */
6844}
6845
6846 void
6847fix_indent()
6848{
6849 if (p_paste)
6850 return;
6851# ifdef FEAT_LISP
6852 if (curbuf->b_p_lisp && curbuf->b_p_ai)
6853 fixthisline(get_lisp_indent);
6854# endif
6855# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
6856 else
6857# endif
6858# ifdef FEAT_CINDENT
6859 if (cindent_on())
6860 do_c_expr_indent();
6861# endif
6862}
6863
6864#endif
6865
6866#ifdef FEAT_CINDENT
6867/*
6868 * return TRUE if 'cinkeys' contains the key "keytyped",
6869 * when == '*': Only if key is preceded with '*' (indent before insert)
6870 * when == '!': Only if key is prededed with '!' (don't insert)
6871 * when == ' ': Only if key is not preceded with '*'(indent afterwards)
6872 *
6873 * "keytyped" can have a few special values:
6874 * KEY_OPEN_FORW
6875 * KEY_OPEN_BACK
6876 * KEY_COMPLETE just finished completion.
6877 *
6878 * If line_is_empty is TRUE accept keys with '0' before them.
6879 */
6880 int
6881in_cinkeys(keytyped, when, line_is_empty)
6882 int keytyped;
6883 int when;
6884 int line_is_empty;
6885{
6886 char_u *look;
6887 int try_match;
6888 int try_match_word;
6889 char_u *p;
6890 char_u *line;
6891 int icase;
6892 int i;
6893
6894#ifdef FEAT_EVAL
6895 if (*curbuf->b_p_inde != NUL)
6896 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
6897 else
6898#endif
6899 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
6900 while (*look)
6901 {
6902 /*
6903 * Find out if we want to try a match with this key, depending on
6904 * 'when' and a '*' or '!' before the key.
6905 */
6906 switch (when)
6907 {
6908 case '*': try_match = (*look == '*'); break;
6909 case '!': try_match = (*look == '!'); break;
6910 default: try_match = (*look != '*'); break;
6911 }
6912 if (*look == '*' || *look == '!')
6913 ++look;
6914
6915 /*
6916 * If there is a '0', only accept a match if the line is empty.
6917 * But may still match when typing last char of a word.
6918 */
6919 if (*look == '0')
6920 {
6921 try_match_word = try_match;
6922 if (!line_is_empty)
6923 try_match = FALSE;
6924 ++look;
6925 }
6926 else
6927 try_match_word = FALSE;
6928
6929 /*
6930 * does it look like a control character?
6931 */
6932 if (*look == '^'
6933#ifdef EBCDIC
6934 && (Ctrl_chr(look[1]) != 0)
6935#else
6936 && look[1] >= '?' && look[1] <= '_'
6937#endif
6938 )
6939 {
6940 if (try_match && keytyped == Ctrl_chr(look[1]))
6941 return TRUE;
6942 look += 2;
6943 }
6944 /*
6945 * 'o' means "o" command, open forward.
6946 * 'O' means "O" command, open backward.
6947 */
6948 else if (*look == 'o')
6949 {
6950 if (try_match && keytyped == KEY_OPEN_FORW)
6951 return TRUE;
6952 ++look;
6953 }
6954 else if (*look == 'O')
6955 {
6956 if (try_match && keytyped == KEY_OPEN_BACK)
6957 return TRUE;
6958 ++look;
6959 }
6960
6961 /*
6962 * 'e' means to check for "else" at start of line and just before the
6963 * cursor.
6964 */
6965 else if (*look == 'e')
6966 {
6967 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
6968 {
6969 p = ml_get_curline();
6970 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
6971 STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
6972 return TRUE;
6973 }
6974 ++look;
6975 }
6976
6977 /*
6978 * ':' only causes an indent if it is at the end of a label or case
6979 * statement, or when it was before typing the ':' (to fix
6980 * class::method for C++).
6981 */
6982 else if (*look == ':')
6983 {
6984 if (try_match && keytyped == ':')
6985 {
6986 p = ml_get_curline();
6987 if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
6988 return TRUE;
6989 if (curwin->w_cursor.col > 2
6990 && p[curwin->w_cursor.col - 1] == ':'
6991 && p[curwin->w_cursor.col - 2] == ':')
6992 {
6993 p[curwin->w_cursor.col - 1] = ' ';
6994 i = (cin_iscase(p) || cin_isscopedecl(p)
6995 || cin_islabel(30));
6996 p = ml_get_curline();
6997 p[curwin->w_cursor.col - 1] = ':';
6998 if (i)
6999 return TRUE;
7000 }
7001 }
7002 ++look;
7003 }
7004
7005
7006 /*
7007 * Is it a key in <>, maybe?
7008 */
7009 else if (*look == '<')
7010 {
7011 if (try_match)
7012 {
7013 /*
7014 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
7015 * <:> and <!> so that people can re-indent on o, O, e, 0, <,
7016 * >, *, : and ! keys if they really really want to.
7017 */
7018 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
7019 && keytyped == look[1])
7020 return TRUE;
7021
7022 if (keytyped == get_special_key_code(look + 1))
7023 return TRUE;
7024 }
7025 while (*look && *look != '>')
7026 look++;
7027 while (*look == '>')
7028 look++;
7029 }
7030
7031 /*
7032 * Is it a word: "=word"?
7033 */
7034 else if (*look == '=' && look[1] != ',' && look[1] != NUL)
7035 {
7036 ++look;
7037 if (*look == '~')
7038 {
7039 icase = TRUE;
7040 ++look;
7041 }
7042 else
7043 icase = FALSE;
7044 p = vim_strchr(look, ',');
7045 if (p == NULL)
7046 p = look + STRLEN(look);
7047 if ((try_match || try_match_word)
7048 && curwin->w_cursor.col >= (colnr_T)(p - look))
7049 {
7050 int match = FALSE;
7051
7052#ifdef FEAT_INS_EXPAND
7053 if (keytyped == KEY_COMPLETE)
7054 {
7055 char_u *s;
7056
7057 /* Just completed a word, check if it starts with "look".
7058 * search back for the start of a word. */
7059 line = ml_get_curline();
7060# ifdef FEAT_MBYTE
7061 if (has_mbyte)
7062 {
7063 char_u *n;
7064
7065 for (s = line + curwin->w_cursor.col; s > line; s = n)
7066 {
7067 n = mb_prevptr(line, s);
7068 if (!vim_iswordp(n))
7069 break;
7070 }
7071 }
7072 else
7073# endif
7074 for (s = line + curwin->w_cursor.col; s > line; --s)
7075 if (!vim_iswordc(s[-1]))
7076 break;
7077 if (s + (p - look) <= line + curwin->w_cursor.col
7078 && (icase
7079 ? MB_STRNICMP(s, look, p - look)
7080 : STRNCMP(s, look, p - look)) == 0)
7081 match = TRUE;
7082 }
7083 else
7084#endif
7085 /* TODO: multi-byte */
7086 if (keytyped == (int)p[-1] || (icase && keytyped < 256
7087 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
7088 {
7089 line = ml_get_cursor();
7090 if ((curwin->w_cursor.col == (colnr_T)(p - look)
7091 || !vim_iswordc(line[-(p - look) - 1]))
7092 && (icase
7093 ? MB_STRNICMP(line - (p - look), look, p - look)
7094 : STRNCMP(line - (p - look), look, p - look))
7095 == 0)
7096 match = TRUE;
7097 }
7098 if (match && try_match_word && !try_match)
7099 {
7100 /* "0=word": Check if there are only blanks before the
7101 * word. */
7102 line = ml_get_curline();
7103 if ((int)(skipwhite(line) - line) !=
7104 (int)(curwin->w_cursor.col - (p - look)))
7105 match = FALSE;
7106 }
7107 if (match)
7108 return TRUE;
7109 }
7110 look = p;
7111 }
7112
7113 /*
7114 * ok, it's a boring generic character.
7115 */
7116 else
7117 {
7118 if (try_match && *look == keytyped)
7119 return TRUE;
7120 ++look;
7121 }
7122
7123 /*
7124 * Skip over ", ".
7125 */
7126 look = skip_to_option_part(look);
7127 }
7128 return FALSE;
7129}
7130#endif /* FEAT_CINDENT */
7131
7132#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
7133/*
7134 * Map Hebrew keyboard when in hkmap mode.
7135 */
7136 int
7137hkmap(c)
7138 int c;
7139{
7140 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
7141 {
7142 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
7143 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
7144 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
7145 static char_u map[26] =
7146 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
7147 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
7148 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
7149 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
7150 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
7151 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
7152 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
7153 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
7154 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
7155
7156 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
7157 return (int)(map[CharOrd(c)] - 1 + p_aleph);
7158 /* '-1'='sofit' */
7159 else if (c == 'x')
7160 return 'X';
7161 else if (c == 'q')
7162 return '\''; /* {geresh}={'} */
7163 else if (c == 246)
7164 return ' '; /* \"o --> ' ' for a german keyboard */
7165 else if (c == 228)
7166 return ' '; /* \"a --> ' ' -- / -- */
7167 else if (c == 252)
7168 return ' '; /* \"u --> ' ' -- / -- */
7169#ifdef EBCDIC
7170 else if (islower(c))
7171#else
7172 /* NOTE: islower() does not do the right thing for us on Linux so we
7173 * do this the same was as 5.7 and previous, so it works correctly on
7174 * all systems. Specifically, the e.g. Delete and Arrow keys are
7175 * munged and won't work if e.g. searching for Hebrew text.
7176 */
7177 else if (c >= 'a' && c <= 'z')
7178#endif
7179 return (int)(map[CharOrdLow(c)] + p_aleph);
7180 else
7181 return c;
7182 }
7183 else
7184 {
7185 switch (c)
7186 {
7187 case '`': return ';';
7188 case '/': return '.';
7189 case '\'': return ',';
7190 case 'q': return '/';
7191 case 'w': return '\'';
7192
7193 /* Hebrew letters - set offset from 'a' */
7194 case ',': c = '{'; break;
7195 case '.': c = 'v'; break;
7196 case ';': c = 't'; break;
7197 default: {
7198 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
7199
7200#ifdef EBCDIC
7201 /* see note about islower() above */
7202 if (!islower(c))
7203#else
7204 if (c < 'a' || c > 'z')
7205#endif
7206 return c;
7207 c = str[CharOrdLow(c)];
7208 break;
7209 }
7210 }
7211
7212 return (int)(CharOrdLow(c) + p_aleph);
7213 }
7214}
7215#endif
7216
7217 static void
7218ins_reg()
7219{
7220 int need_redraw = FALSE;
7221 int regname;
7222 int literally = 0;
7223
7224 /*
7225 * If we are going to wait for a character, show a '"'.
7226 */
7227 pc_status = PC_STATUS_UNSET;
7228 if (redrawing() && !char_avail())
7229 {
7230 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007231 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007232
7233 edit_putchar('"', TRUE);
7234#ifdef FEAT_CMDL_INFO
7235 add_to_showcmd_c(Ctrl_R);
7236#endif
7237 }
7238
7239#ifdef USE_ON_FLY_SCROLL
7240 dont_scroll = TRUE; /* disallow scrolling here */
7241#endif
7242
7243 /*
7244 * Don't map the register name. This also prevents the mode message to be
7245 * deleted when ESC is hit.
7246 */
7247 ++no_mapping;
7248 regname = safe_vgetc();
7249#ifdef FEAT_LANGMAP
7250 LANGMAP_ADJUST(regname, TRUE);
7251#endif
7252 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
7253 {
7254 /* Get a third key for literal register insertion */
7255 literally = regname;
7256#ifdef FEAT_CMDL_INFO
7257 add_to_showcmd_c(literally);
7258#endif
7259 regname = safe_vgetc();
7260#ifdef FEAT_LANGMAP
7261 LANGMAP_ADJUST(regname, TRUE);
7262#endif
7263 }
7264 --no_mapping;
7265
7266#ifdef FEAT_EVAL
7267 /*
7268 * Don't call u_sync() while getting the expression,
7269 * evaluating it or giving an error message for it!
7270 */
7271 ++no_u_sync;
7272 if (regname == '=')
7273 {
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007274# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007275 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007276# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007277 regname = get_expr_register();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007278# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007279 /* Restore the Input Method. */
7280 if (im_on)
7281 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007282# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007283 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00007284 if (regname == NUL || !valid_yank_reg(regname, FALSE))
7285 {
7286 vim_beep();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007287 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00007288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007289 else
7290 {
7291#endif
7292 if (literally == Ctrl_O || literally == Ctrl_P)
7293 {
7294 /* Append the command to the redo buffer. */
7295 AppendCharToRedobuff(Ctrl_R);
7296 AppendCharToRedobuff(literally);
7297 AppendCharToRedobuff(regname);
7298
7299 do_put(regname, BACKWARD, 1L,
7300 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
7301 }
7302 else if (insert_reg(regname, literally) == FAIL)
7303 {
7304 vim_beep();
7305 need_redraw = TRUE; /* remove the '"' */
7306 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007307 else if (stop_insert_mode)
7308 /* When the '=' register was used and a function was invoked that
7309 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
7310 * insert anything, need to remove the '"' */
7311 need_redraw = TRUE;
7312
Bram Moolenaar071d4272004-06-13 20:20:40 +00007313#ifdef FEAT_EVAL
7314 }
7315 --no_u_sync;
7316#endif
7317#ifdef FEAT_CMDL_INFO
7318 clear_showcmd();
7319#endif
7320
7321 /* If the inserted register is empty, we need to remove the '"' */
7322 if (need_redraw || stuff_empty())
7323 edit_unputchar();
7324}
7325
7326/*
7327 * CTRL-G commands in Insert mode.
7328 */
7329 static void
7330ins_ctrl_g()
7331{
7332 int c;
7333
7334#ifdef FEAT_INS_EXPAND
7335 /* Right after CTRL-X the cursor will be after the ruler. */
7336 setcursor();
7337#endif
7338
7339 /*
7340 * Don't map the second key. This also prevents the mode message to be
7341 * deleted when ESC is hit.
7342 */
7343 ++no_mapping;
7344 c = safe_vgetc();
7345 --no_mapping;
7346 switch (c)
7347 {
7348 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
7349 case K_UP:
7350 case Ctrl_K:
7351 case 'k': ins_up(TRUE);
7352 break;
7353
7354 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
7355 case K_DOWN:
7356 case Ctrl_J:
7357 case 'j': ins_down(TRUE);
7358 break;
7359
7360 /* CTRL-G u: start new undoable edit */
Bram Moolenaar779b74b2006-04-10 14:55:34 +00007361 case 'u': u_sync(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007362 ins_need_undo = TRUE;
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00007363
7364 /* Need to reset Insstart, esp. because a BS that joins
7365 * aline to the previous one must save for undo. */
7366 Insstart = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007367 break;
7368
7369 /* Unknown CTRL-G command, reserved for future expansion. */
7370 default: vim_beep();
7371 }
7372}
7373
7374/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007375 * CTRL-^ in Insert mode.
7376 */
7377 static void
7378ins_ctrl_hat()
7379{
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00007380 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007381 {
7382 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
7383 if (State & LANGMAP)
7384 {
7385 curbuf->b_p_iminsert = B_IMODE_NONE;
7386 State &= ~LANGMAP;
7387 }
7388 else
7389 {
7390 curbuf->b_p_iminsert = B_IMODE_LMAP;
7391 State |= LANGMAP;
7392#ifdef USE_IM_CONTROL
7393 im_set_active(FALSE);
7394#endif
7395 }
7396 }
7397#ifdef USE_IM_CONTROL
7398 else
7399 {
7400 /* There are no ":lmap" mappings, toggle IM */
7401 if (im_get_status())
7402 {
7403 curbuf->b_p_iminsert = B_IMODE_NONE;
7404 im_set_active(FALSE);
7405 }
7406 else
7407 {
7408 curbuf->b_p_iminsert = B_IMODE_IM;
7409 State &= ~LANGMAP;
7410 im_set_active(TRUE);
7411 }
7412 }
7413#endif
7414 set_iminsert_global();
7415 showmode();
7416#ifdef FEAT_GUI
7417 /* may show different cursor shape or color */
7418 if (gui.in_use)
7419 gui_update_cursor(TRUE, FALSE);
7420#endif
7421#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
7422 /* Show/unshow value of 'keymap' in status lines. */
7423 status_redraw_curbuf();
7424#endif
7425}
7426
7427/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007428 * Handle ESC in insert mode.
7429 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
7430 * insert.
7431 */
7432 static int
Bram Moolenaar488c6512005-08-11 20:09:58 +00007433ins_esc(count, cmdchar, nomove)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007434 long *count;
7435 int cmdchar;
Bram Moolenaar488c6512005-08-11 20:09:58 +00007436 int nomove; /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007437{
7438 int temp;
7439 static int disabled_redraw = FALSE;
7440
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00007441#ifdef FEAT_SPELL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007442 check_spell_redraw();
7443#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007444#if defined(FEAT_HANGULIN)
7445# if defined(ESC_CHG_TO_ENG_MODE)
7446 hangul_input_state_set(0);
7447# endif
7448 if (composing_hangul)
7449 {
7450 push_raw_key(composing_hangul_buffer, 2);
7451 composing_hangul = 0;
7452 }
7453#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007454
7455 temp = curwin->w_cursor.col;
7456 if (disabled_redraw)
7457 {
7458 --RedrawingDisabled;
7459 disabled_redraw = FALSE;
7460 }
7461 if (!arrow_used)
7462 {
7463 /*
7464 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00007465 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
7466 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007467 */
7468 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00007469 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007470
7471 /*
7472 * Repeating insert may take a long time. Check for
7473 * interrupt now and then.
7474 */
7475 if (*count > 0)
7476 {
7477 line_breakcheck();
7478 if (got_int)
7479 *count = 0;
7480 }
7481
7482 if (--*count > 0) /* repeat what was typed */
7483 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00007484 /* Vi repeats the insert without replacing characters. */
7485 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
7486 State &= ~REPLACE_FLAG;
7487
Bram Moolenaar071d4272004-06-13 20:20:40 +00007488 (void)start_redo_ins();
7489 if (cmdchar == 'r' || cmdchar == 'v')
7490 stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
7491 ++RedrawingDisabled;
7492 disabled_redraw = TRUE;
7493 return FALSE; /* repeat the insert */
7494 }
7495 stop_insert(&curwin->w_cursor, TRUE);
7496 undisplay_dollar();
7497 }
7498
7499 /* When an autoindent was removed, curswant stays after the
7500 * indent */
7501 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
7502 curwin->w_set_curswant = TRUE;
7503
7504 /* Remember the last Insert position in the '^ mark. */
7505 if (!cmdmod.keepjumps)
7506 curbuf->b_last_insert = curwin->w_cursor;
7507
7508 /*
7509 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00007510 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007511 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00007512 if (!nomove
7513 && (curwin->w_cursor.col != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007514#ifdef FEAT_VIRTUALEDIT
7515 || curwin->w_cursor.coladd > 0
7516#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007517 )
7518 && (restart_edit == NUL
7519 || (gchar_cursor() == NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007520#ifdef FEAT_VISUAL
Bram Moolenaar488c6512005-08-11 20:09:58 +00007521 && !VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +00007522#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007523 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007524#ifdef FEAT_RIGHTLEFT
7525 && !revins_on
7526#endif
7527 )
7528 {
7529#ifdef FEAT_VIRTUALEDIT
7530 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
7531 {
7532 oneleft();
7533 if (restart_edit != NUL)
7534 ++curwin->w_cursor.coladd;
7535 }
7536 else
7537#endif
7538 {
7539 --curwin->w_cursor.col;
7540#ifdef FEAT_MBYTE
7541 /* Correct cursor for multi-byte character. */
7542 if (has_mbyte)
7543 mb_adjust_cursor();
7544#endif
7545 }
7546 }
7547
7548#ifdef USE_IM_CONTROL
7549 /* Disable IM to allow typing English directly for Normal mode commands.
7550 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
7551 * well). */
7552 if (!(State & LANGMAP))
7553 im_save_status(&curbuf->b_p_iminsert);
7554 im_set_active(FALSE);
7555#endif
7556
7557 State = NORMAL;
7558 /* need to position cursor again (e.g. when on a TAB ) */
7559 changed_cline_bef_curs();
7560
7561#ifdef FEAT_MOUSE
7562 setmouse();
7563#endif
7564#ifdef CURSOR_SHAPE
7565 ui_cursor_shape(); /* may show different cursor shape */
7566#endif
7567
7568 /*
7569 * When recording or for CTRL-O, need to display the new mode.
7570 * Otherwise remove the mode message.
7571 */
7572 if (Recording || restart_edit != NUL)
7573 showmode();
7574 else if (p_smd)
7575 MSG("");
7576
7577 return TRUE; /* exit Insert mode */
7578}
7579
7580#ifdef FEAT_RIGHTLEFT
7581/*
7582 * Toggle language: hkmap and revins_on.
7583 * Move to end of reverse inserted text.
7584 */
7585 static void
7586ins_ctrl_()
7587{
7588 if (revins_on && revins_chars && revins_scol >= 0)
7589 {
7590 while (gchar_cursor() != NUL && revins_chars--)
7591 ++curwin->w_cursor.col;
7592 }
7593 p_ri = !p_ri;
7594 revins_on = (State == INSERT && p_ri);
7595 if (revins_on)
7596 {
7597 revins_scol = curwin->w_cursor.col;
7598 revins_legal++;
7599 revins_chars = 0;
7600 undisplay_dollar();
7601 }
7602 else
7603 revins_scol = -1;
7604#ifdef FEAT_FKMAP
7605 if (p_altkeymap)
7606 {
7607 /*
7608 * to be consistent also for redo command, using '.'
7609 * set arrow_used to true and stop it - causing to redo
7610 * characters entered in one mode (normal/reverse insert).
7611 */
7612 arrow_used = TRUE;
7613 (void)stop_arrow();
7614 p_fkmap = curwin->w_p_rl ^ p_ri;
7615 if (p_fkmap && p_ri)
7616 State = INSERT;
7617 }
7618 else
7619#endif
7620 p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
7621 showmode();
7622}
7623#endif
7624
7625#ifdef FEAT_VISUAL
7626/*
7627 * If 'keymodel' contains "startsel", may start selection.
7628 * Returns TRUE when a CTRL-O and other keys stuffed.
7629 */
7630 static int
7631ins_start_select(c)
7632 int c;
7633{
7634 if (km_startsel)
7635 switch (c)
7636 {
7637 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007638 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007639 case K_PAGEUP:
7640 case K_KPAGEUP:
7641 case K_PAGEDOWN:
7642 case K_KPAGEDOWN:
7643# ifdef MACOS
7644 case K_LEFT:
7645 case K_RIGHT:
7646 case K_UP:
7647 case K_DOWN:
7648 case K_END:
7649 case K_HOME:
7650# endif
7651 if (!(mod_mask & MOD_MASK_SHIFT))
7652 break;
7653 /* FALLTHROUGH */
7654 case K_S_LEFT:
7655 case K_S_RIGHT:
7656 case K_S_UP:
7657 case K_S_DOWN:
7658 case K_S_END:
7659 case K_S_HOME:
7660 /* Start selection right away, the cursor can move with
7661 * CTRL-O when beyond the end of the line. */
7662 start_selection();
7663
7664 /* Execute the key in (insert) Select mode. */
7665 stuffcharReadbuff(Ctrl_O);
7666 if (mod_mask)
7667 {
7668 char_u buf[4];
7669
7670 buf[0] = K_SPECIAL;
7671 buf[1] = KS_MODIFIER;
7672 buf[2] = mod_mask;
7673 buf[3] = NUL;
7674 stuffReadbuff(buf);
7675 }
7676 stuffcharReadbuff(c);
7677 return TRUE;
7678 }
7679 return FALSE;
7680}
7681#endif
7682
7683/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007684 * <Insert> key in Insert mode: toggle insert/remplace mode.
7685 */
7686 static void
7687ins_insert(replaceState)
7688 int replaceState;
7689{
7690#ifdef FEAT_FKMAP
7691 if (p_fkmap && p_ri)
7692 {
7693 beep_flush();
7694 EMSG(farsi_text_3); /* encoded in Farsi */
7695 return;
7696 }
7697#endif
7698
7699#ifdef FEAT_AUTOCMD
Bram Moolenaar1e015462005-09-25 22:16:38 +00007700# ifdef FEAT_EVAL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007701 set_vim_var_string(VV_INSERTMODE,
7702 (char_u *)((State & REPLACE_FLAG) ? "i" :
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00007703# ifdef FEAT_VREPLACE
7704 replaceState == VREPLACE ? "v" :
7705# endif
7706 "r"), 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00007707# endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007708 apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
7709#endif
7710 if (State & REPLACE_FLAG)
7711 State = INSERT | (State & LANGMAP);
7712 else
7713 State = replaceState | (State & LANGMAP);
7714 AppendCharToRedobuff(K_INS);
7715 showmode();
7716#ifdef CURSOR_SHAPE
7717 ui_cursor_shape(); /* may show different cursor shape */
7718#endif
7719}
7720
7721/*
7722 * Pressed CTRL-O in Insert mode.
7723 */
7724 static void
7725ins_ctrl_o()
7726{
7727#ifdef FEAT_VREPLACE
7728 if (State & VREPLACE_FLAG)
7729 restart_edit = 'V';
7730 else
7731#endif
7732 if (State & REPLACE_FLAG)
7733 restart_edit = 'R';
7734 else
7735 restart_edit = 'I';
7736#ifdef FEAT_VIRTUALEDIT
7737 if (virtual_active())
7738 ins_at_eol = FALSE; /* cursor always keeps its column */
7739 else
7740#endif
7741 ins_at_eol = (gchar_cursor() == NUL);
7742}
7743
7744/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007745 * If the cursor is on an indent, ^T/^D insert/delete one
7746 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
7747 * Always round the indent to 'shiftwith', this is compatible
7748 * with vi. But vi only supports ^T and ^D after an
7749 * autoindent, we support it everywhere.
7750 */
7751 static void
7752ins_shift(c, lastc)
7753 int c;
7754 int lastc;
7755{
7756 if (stop_arrow() == FAIL)
7757 return;
7758 AppendCharToRedobuff(c);
7759
7760 /*
7761 * 0^D and ^^D: remove all indent.
7762 */
7763 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
7764 {
7765 --curwin->w_cursor.col;
7766 (void)del_char(FALSE); /* delete the '^' or '0' */
7767 /* In Replace mode, restore the characters that '^' or '0' replaced. */
7768 if (State & REPLACE_FLAG)
7769 replace_pop_ins();
7770 if (lastc == '^')
7771 old_indent = get_indent(); /* remember curr. indent */
7772 change_indent(INDENT_SET, 0, TRUE, 0);
7773 }
7774 else
7775 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
7776
7777 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
7778 did_ai = FALSE;
7779#ifdef FEAT_SMARTINDENT
7780 did_si = FALSE;
7781 can_si = FALSE;
7782 can_si_back = FALSE;
7783#endif
7784#ifdef FEAT_CINDENT
7785 can_cindent = FALSE; /* no cindenting after ^D or ^T */
7786#endif
7787}
7788
7789 static void
7790ins_del()
7791{
7792 int temp;
7793
7794 if (stop_arrow() == FAIL)
7795 return;
7796 if (gchar_cursor() == NUL) /* delete newline */
7797 {
7798 temp = curwin->w_cursor.col;
7799 if (!can_bs(BS_EOL) /* only if "eol" included */
7800 || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
7801 (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
7802 || do_join(FALSE) == FAIL)
7803 vim_beep();
7804 else
7805 curwin->w_cursor.col = temp;
7806 }
7807 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
7808 vim_beep();
7809 did_ai = FALSE;
7810#ifdef FEAT_SMARTINDENT
7811 did_si = FALSE;
7812 can_si = FALSE;
7813 can_si_back = FALSE;
7814#endif
7815 AppendCharToRedobuff(K_DEL);
7816}
7817
7818/*
7819 * Handle Backspace, delete-word and delete-line in Insert mode.
7820 * Return TRUE when backspace was actually used.
7821 */
7822 static int
7823ins_bs(c, mode, inserted_space_p)
7824 int c;
7825 int mode;
7826 int *inserted_space_p;
7827{
7828 linenr_T lnum;
7829 int cc;
7830 int temp = 0; /* init for GCC */
7831 colnr_T mincol;
7832 int did_backspace = FALSE;
7833 int in_indent;
7834 int oldState;
7835#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007836 int cpc[MAX_MCO]; /* composing characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007837#endif
7838
7839 /*
7840 * can't delete anything in an empty file
7841 * can't backup past first character in buffer
7842 * can't backup past starting point unless 'backspace' > 1
7843 * can backup to a previous line if 'backspace' == 0
7844 */
7845 if ( bufempty()
7846 || (
7847#ifdef FEAT_RIGHTLEFT
7848 !revins_on &&
7849#endif
7850 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
7851 || (!can_bs(BS_START)
7852 && (arrow_used
7853 || (curwin->w_cursor.lnum == Insstart.lnum
7854 && curwin->w_cursor.col <= Insstart.col)))
7855 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
7856 && curwin->w_cursor.col <= ai_col)
7857 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
7858 {
7859 vim_beep();
7860 return FALSE;
7861 }
7862
7863 if (stop_arrow() == FAIL)
7864 return FALSE;
7865 in_indent = inindent(0);
7866#ifdef FEAT_CINDENT
7867 if (in_indent)
7868 can_cindent = FALSE;
7869#endif
7870#ifdef FEAT_COMMENTS
7871 end_comment_pending = NUL; /* After BS, don't auto-end comment */
7872#endif
7873#ifdef FEAT_RIGHTLEFT
7874 if (revins_on) /* put cursor after last inserted char */
7875 inc_cursor();
7876#endif
7877
7878#ifdef FEAT_VIRTUALEDIT
7879 /* Virtualedit:
7880 * BACKSPACE_CHAR eats a virtual space
7881 * BACKSPACE_WORD eats all coladd
7882 * BACKSPACE_LINE eats all coladd and keeps going
7883 */
7884 if (curwin->w_cursor.coladd > 0)
7885 {
7886 if (mode == BACKSPACE_CHAR)
7887 {
7888 --curwin->w_cursor.coladd;
7889 return TRUE;
7890 }
7891 if (mode == BACKSPACE_WORD)
7892 {
7893 curwin->w_cursor.coladd = 0;
7894 return TRUE;
7895 }
7896 curwin->w_cursor.coladd = 0;
7897 }
7898#endif
7899
7900 /*
7901 * delete newline!
7902 */
7903 if (curwin->w_cursor.col == 0)
7904 {
7905 lnum = Insstart.lnum;
7906 if (curwin->w_cursor.lnum == Insstart.lnum
7907#ifdef FEAT_RIGHTLEFT
7908 || revins_on
7909#endif
7910 )
7911 {
7912 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
7913 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
7914 return FALSE;
7915 --Insstart.lnum;
7916 Insstart.col = MAXCOL;
7917 }
7918 /*
7919 * In replace mode:
7920 * cc < 0: NL was inserted, delete it
7921 * cc >= 0: NL was replaced, put original characters back
7922 */
7923 cc = -1;
7924 if (State & REPLACE_FLAG)
7925 cc = replace_pop(); /* returns -1 if NL was inserted */
7926 /*
7927 * In replace mode, in the line we started replacing, we only move the
7928 * cursor.
7929 */
7930 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
7931 {
7932 dec_cursor();
7933 }
7934 else
7935 {
7936#ifdef FEAT_VREPLACE
7937 if (!(State & VREPLACE_FLAG)
7938 || curwin->w_cursor.lnum > orig_line_count)
7939#endif
7940 {
7941 temp = gchar_cursor(); /* remember current char */
7942 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00007943
7944 /* When "aw" is in 'formatoptions' we must delete the space at
7945 * the end of the line, otherwise the line will be broken
7946 * again when auto-formatting. */
7947 if (has_format_option(FO_AUTO)
7948 && has_format_option(FO_WHITE_PAR))
7949 {
7950 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
7951 TRUE);
7952 int len;
7953
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00007954 len = (int)STRLEN(ptr);
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00007955 if (len > 0 && ptr[len - 1] == ' ')
7956 ptr[len - 1] = NUL;
7957 }
7958
Bram Moolenaar071d4272004-06-13 20:20:40 +00007959 (void)do_join(FALSE);
7960 if (temp == NUL && gchar_cursor() != NUL)
7961 inc_cursor();
7962 }
7963#ifdef FEAT_VREPLACE
7964 else
7965 dec_cursor();
7966#endif
7967
7968 /*
7969 * In REPLACE mode we have to put back the text that was replaced
7970 * by the NL. On the replace stack is first a NUL-terminated
7971 * sequence of characters that were deleted and then the
7972 * characters that NL replaced.
7973 */
7974 if (State & REPLACE_FLAG)
7975 {
7976 /*
7977 * Do the next ins_char() in NORMAL state, to
7978 * prevent ins_char() from replacing characters and
7979 * avoiding showmatch().
7980 */
7981 oldState = State;
7982 State = NORMAL;
7983 /*
7984 * restore characters (blanks) deleted after cursor
7985 */
7986 while (cc > 0)
7987 {
7988 temp = curwin->w_cursor.col;
7989#ifdef FEAT_MBYTE
7990 mb_replace_pop_ins(cc);
7991#else
7992 ins_char(cc);
7993#endif
7994 curwin->w_cursor.col = temp;
7995 cc = replace_pop();
7996 }
7997 /* restore the characters that NL replaced */
7998 replace_pop_ins();
7999 State = oldState;
8000 }
8001 }
8002 did_ai = FALSE;
8003 }
8004 else
8005 {
8006 /*
8007 * Delete character(s) before the cursor.
8008 */
8009#ifdef FEAT_RIGHTLEFT
8010 if (revins_on) /* put cursor on last inserted char */
8011 dec_cursor();
8012#endif
8013 mincol = 0;
8014 /* keep indent */
8015 if (mode == BACKSPACE_LINE && curbuf->b_p_ai
8016#ifdef FEAT_RIGHTLEFT
8017 && !revins_on
8018#endif
8019 )
8020 {
8021 temp = curwin->w_cursor.col;
8022 beginline(BL_WHITE);
8023 if (curwin->w_cursor.col < (colnr_T)temp)
8024 mincol = curwin->w_cursor.col;
8025 curwin->w_cursor.col = temp;
8026 }
8027
8028 /*
8029 * Handle deleting one 'shiftwidth' or 'softtabstop'.
8030 */
8031 if ( mode == BACKSPACE_CHAR
8032 && ((p_sta && in_indent)
Bram Moolenaar280f1262006-01-30 00:14:18 +00008033 || (curbuf->b_p_sts != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008034 && (*(ml_get_cursor() - 1) == TAB
8035 || (*(ml_get_cursor() - 1) == ' '
8036 && (!*inserted_space_p
8037 || arrow_used))))))
8038 {
8039 int ts;
8040 colnr_T vcol;
8041 colnr_T want_vcol;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008042#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008043 int extra = 0;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008044#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008045
8046 *inserted_space_p = FALSE;
Bram Moolenaar280f1262006-01-30 00:14:18 +00008047 if (p_sta && in_indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008048 ts = curbuf->b_p_sw;
8049 else
8050 ts = curbuf->b_p_sts;
8051 /* Compute the virtual column where we want to be. Since
8052 * 'showbreak' may get in the way, need to get the last column of
8053 * the previous character. */
8054 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8055 dec_cursor();
8056 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
8057 inc_cursor();
8058 want_vcol = (want_vcol / ts) * ts;
8059
8060 /* delete characters until we are at or before want_vcol */
8061 while (vcol > want_vcol
8062 && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
8063 {
8064 dec_cursor();
8065 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8066 if (State & REPLACE_FLAG)
8067 {
8068 /* Don't delete characters before the insert point when in
8069 * Replace mode */
8070 if (curwin->w_cursor.lnum != Insstart.lnum
8071 || curwin->w_cursor.col >= Insstart.col)
8072 {
8073#if 0 /* what was this for? It causes problems when sw != ts. */
8074 if (State == REPLACE && (int)vcol < want_vcol)
8075 {
8076 (void)del_char(FALSE);
8077 extra = 2; /* don't pop too much */
8078 }
8079 else
8080#endif
8081 replace_do_bs();
8082 }
8083 }
8084 else
8085 (void)del_char(FALSE);
8086 }
8087
8088 /* insert extra spaces until we are at want_vcol */
8089 while (vcol < want_vcol)
8090 {
8091 /* Remember the first char we inserted */
8092 if (curwin->w_cursor.lnum == Insstart.lnum
8093 && curwin->w_cursor.col < Insstart.col)
8094 Insstart.col = curwin->w_cursor.col;
8095
8096#ifdef FEAT_VREPLACE
8097 if (State & VREPLACE_FLAG)
8098 ins_char(' ');
8099 else
8100#endif
8101 {
8102 ins_str((char_u *)" ");
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008103 if ((State & REPLACE_FLAG) /* && extra <= 1 */)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008104 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008105#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008106 if (extra)
8107 replace_push_off(NUL);
8108 else
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008109#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008110 replace_push(NUL);
8111 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008112#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008113 if (extra == 2)
8114 extra = 1;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008115#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008116 }
8117 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8118 }
8119 }
8120
8121 /*
8122 * Delete upto starting point, start of line or previous word.
8123 */
8124 else do
8125 {
8126#ifdef FEAT_RIGHTLEFT
8127 if (!revins_on) /* put cursor on char to be deleted */
8128#endif
8129 dec_cursor();
8130
8131 /* start of word? */
8132 if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
8133 {
8134 mode = BACKSPACE_WORD_NOT_SPACE;
8135 temp = vim_iswordc(gchar_cursor());
8136 }
8137 /* end of word? */
8138 else if (mode == BACKSPACE_WORD_NOT_SPACE
8139 && (vim_isspace(cc = gchar_cursor())
8140 || vim_iswordc(cc) != temp))
8141 {
8142#ifdef FEAT_RIGHTLEFT
8143 if (!revins_on)
8144#endif
8145 inc_cursor();
8146#ifdef FEAT_RIGHTLEFT
8147 else if (State & REPLACE_FLAG)
8148 dec_cursor();
8149#endif
8150 break;
8151 }
8152 if (State & REPLACE_FLAG)
8153 replace_do_bs();
8154 else
8155 {
8156#ifdef FEAT_MBYTE
8157 if (enc_utf8 && p_deco)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008158 (void)utfc_ptr2char(ml_get_cursor(), cpc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008159#endif
8160 (void)del_char(FALSE);
8161#ifdef FEAT_MBYTE
8162 /*
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008163 * If there are combining characters and 'delcombine' is set
8164 * move the cursor back. Don't back up before the base
Bram Moolenaar071d4272004-06-13 20:20:40 +00008165 * character.
8166 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008167 if (enc_utf8 && p_deco && cpc[0] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008168 inc_cursor();
8169#endif
8170#ifdef FEAT_RIGHTLEFT
8171 if (revins_chars)
8172 {
8173 revins_chars--;
8174 revins_legal++;
8175 }
8176 if (revins_on && gchar_cursor() == NUL)
8177 break;
8178#endif
8179 }
8180 /* Just a single backspace?: */
8181 if (mode == BACKSPACE_CHAR)
8182 break;
8183 } while (
8184#ifdef FEAT_RIGHTLEFT
8185 revins_on ||
8186#endif
8187 (curwin->w_cursor.col > mincol
8188 && (curwin->w_cursor.lnum != Insstart.lnum
8189 || curwin->w_cursor.col != Insstart.col)));
8190 did_backspace = TRUE;
8191 }
8192#ifdef FEAT_SMARTINDENT
8193 did_si = FALSE;
8194 can_si = FALSE;
8195 can_si_back = FALSE;
8196#endif
8197 if (curwin->w_cursor.col <= 1)
8198 did_ai = FALSE;
8199 /*
8200 * It's a little strange to put backspaces into the redo
8201 * buffer, but it makes auto-indent a lot easier to deal
8202 * with.
8203 */
8204 AppendCharToRedobuff(c);
8205
8206 /* If deleted before the insertion point, adjust it */
8207 if (curwin->w_cursor.lnum == Insstart.lnum
8208 && curwin->w_cursor.col < Insstart.col)
8209 Insstart.col = curwin->w_cursor.col;
8210
8211 /* vi behaviour: the cursor moves backward but the character that
8212 * was there remains visible
8213 * Vim behaviour: the cursor moves backward and the character that
8214 * was there is erased from the screen.
8215 * We can emulate the vi behaviour by pretending there is a dollar
8216 * displayed even when there isn't.
8217 * --pkv Sun Jan 19 01:56:40 EST 2003 */
8218 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == 0)
8219 dollar_vcol = curwin->w_virtcol;
8220
8221 return did_backspace;
8222}
8223
8224#ifdef FEAT_MOUSE
8225 static void
8226ins_mouse(c)
8227 int c;
8228{
8229 pos_T tpos;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008230 win_T *old_curwin = curwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008231
8232# ifdef FEAT_GUI
8233 /* When GUI is active, also move/paste when 'mouse' is empty */
8234 if (!gui.in_use)
8235# endif
8236 if (!mouse_has(MOUSE_INSERT))
8237 return;
8238
8239 undisplay_dollar();
8240 tpos = curwin->w_cursor;
8241 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
8242 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008243#ifdef FEAT_WINDOWS
8244 win_T *new_curwin = curwin;
8245
8246 if (curwin != old_curwin && win_valid(old_curwin))
8247 {
8248 /* Mouse took us to another window. We need to go back to the
8249 * previous one to stop insert there properly. */
8250 curwin = old_curwin;
8251 curbuf = curwin->w_buffer;
8252 }
8253#endif
8254 start_arrow(curwin == old_curwin ? &tpos : NULL);
8255#ifdef FEAT_WINDOWS
8256 if (curwin != new_curwin && win_valid(new_curwin))
8257 {
8258 curwin = new_curwin;
8259 curbuf = curwin->w_buffer;
8260 }
8261#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008262# ifdef FEAT_CINDENT
8263 can_cindent = TRUE;
8264# endif
8265 }
8266
8267#ifdef FEAT_WINDOWS
8268 /* redraw status lines (in case another window became active) */
8269 redraw_statuslines();
8270#endif
8271}
8272
8273 static void
8274ins_mousescroll(up)
8275 int up;
8276{
8277 pos_T tpos;
8278# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8279 win_T *old_curwin;
8280# endif
8281
8282 tpos = curwin->w_cursor;
8283
8284# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8285 old_curwin = curwin;
8286
8287 /* Currently the mouse coordinates are only known in the GUI. */
8288 if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
8289 {
8290 int row, col;
8291
8292 row = mouse_row;
8293 col = mouse_col;
8294
8295 /* find the window at the pointer coordinates */
8296 curwin = mouse_find_win(&row, &col);
8297 curbuf = curwin->w_buffer;
8298 }
8299 if (curwin == old_curwin)
8300# endif
8301 undisplay_dollar();
8302
8303 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
8304 scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
8305 else
8306 scroll_redraw(up, 3L);
8307
8308# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8309 curwin->w_redr_status = TRUE;
8310
8311 curwin = old_curwin;
8312 curbuf = curwin->w_buffer;
8313# endif
8314
8315 if (!equalpos(curwin->w_cursor, tpos))
8316 {
8317 start_arrow(&tpos);
8318# ifdef FEAT_CINDENT
8319 can_cindent = TRUE;
8320# endif
8321 }
8322}
8323#endif
8324
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008325#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00008326 static void
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008327ins_tabline(c)
8328 int c;
8329{
8330 /* We will be leaving the current window, unless closing another tab. */
8331 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE
8332 || (current_tab != 0 && current_tab != tabpage_index(curtab)))
8333 {
8334 undisplay_dollar();
8335 start_arrow(&curwin->w_cursor);
8336# ifdef FEAT_CINDENT
8337 can_cindent = TRUE;
8338# endif
8339 }
8340
8341 if (c == K_TABLINE)
8342 goto_tabpage(current_tab);
8343 else
8344 handle_tabmenu();
8345
8346}
8347#endif
8348
8349#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008350 void
8351ins_scroll()
8352{
8353 pos_T tpos;
8354
8355 undisplay_dollar();
8356 tpos = curwin->w_cursor;
8357 if (gui_do_scroll())
8358 {
8359 start_arrow(&tpos);
8360# ifdef FEAT_CINDENT
8361 can_cindent = TRUE;
8362# endif
8363 }
8364}
8365
8366 void
8367ins_horscroll()
8368{
8369 pos_T tpos;
8370
8371 undisplay_dollar();
8372 tpos = curwin->w_cursor;
8373 if (gui_do_horiz_scroll())
8374 {
8375 start_arrow(&tpos);
8376# ifdef FEAT_CINDENT
8377 can_cindent = TRUE;
8378# endif
8379 }
8380}
8381#endif
8382
8383 static void
8384ins_left()
8385{
8386 pos_T tpos;
8387
8388#ifdef FEAT_FOLDING
8389 if ((fdo_flags & FDO_HOR) && KeyTyped)
8390 foldOpenCursor();
8391#endif
8392 undisplay_dollar();
8393 tpos = curwin->w_cursor;
8394 if (oneleft() == OK)
8395 {
8396 start_arrow(&tpos);
8397#ifdef FEAT_RIGHTLEFT
8398 /* If exit reversed string, position is fixed */
8399 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
8400 revins_legal++;
8401 revins_chars++;
8402#endif
8403 }
8404
8405 /*
8406 * if 'whichwrap' set for cursor in insert mode may go to
8407 * previous line
8408 */
8409 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
8410 {
8411 start_arrow(&tpos);
8412 --(curwin->w_cursor.lnum);
8413 coladvance((colnr_T)MAXCOL);
8414 curwin->w_set_curswant = TRUE; /* so we stay at the end */
8415 }
8416 else
8417 vim_beep();
8418}
8419
8420 static void
8421ins_home(c)
8422 int c;
8423{
8424 pos_T tpos;
8425
8426#ifdef FEAT_FOLDING
8427 if ((fdo_flags & FDO_HOR) && KeyTyped)
8428 foldOpenCursor();
8429#endif
8430 undisplay_dollar();
8431 tpos = curwin->w_cursor;
8432 if (c == K_C_HOME)
8433 curwin->w_cursor.lnum = 1;
8434 curwin->w_cursor.col = 0;
8435#ifdef FEAT_VIRTUALEDIT
8436 curwin->w_cursor.coladd = 0;
8437#endif
8438 curwin->w_curswant = 0;
8439 start_arrow(&tpos);
8440}
8441
8442 static void
8443ins_end(c)
8444 int c;
8445{
8446 pos_T tpos;
8447
8448#ifdef FEAT_FOLDING
8449 if ((fdo_flags & FDO_HOR) && KeyTyped)
8450 foldOpenCursor();
8451#endif
8452 undisplay_dollar();
8453 tpos = curwin->w_cursor;
8454 if (c == K_C_END)
8455 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
8456 coladvance((colnr_T)MAXCOL);
8457 curwin->w_curswant = MAXCOL;
8458
8459 start_arrow(&tpos);
8460}
8461
8462 static void
8463ins_s_left()
8464{
8465#ifdef FEAT_FOLDING
8466 if ((fdo_flags & FDO_HOR) && KeyTyped)
8467 foldOpenCursor();
8468#endif
8469 undisplay_dollar();
8470 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
8471 {
8472 start_arrow(&curwin->w_cursor);
8473 (void)bck_word(1L, FALSE, FALSE);
8474 curwin->w_set_curswant = TRUE;
8475 }
8476 else
8477 vim_beep();
8478}
8479
8480 static void
8481ins_right()
8482{
8483#ifdef FEAT_FOLDING
8484 if ((fdo_flags & FDO_HOR) && KeyTyped)
8485 foldOpenCursor();
8486#endif
8487 undisplay_dollar();
8488 if (gchar_cursor() != NUL || virtual_active()
8489 )
8490 {
8491 start_arrow(&curwin->w_cursor);
8492 curwin->w_set_curswant = TRUE;
8493#ifdef FEAT_VIRTUALEDIT
8494 if (virtual_active())
8495 oneright();
8496 else
8497#endif
8498 {
8499#ifdef FEAT_MBYTE
8500 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00008501 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00008502 else
8503#endif
8504 ++curwin->w_cursor.col;
8505 }
8506
8507#ifdef FEAT_RIGHTLEFT
8508 revins_legal++;
8509 if (revins_chars)
8510 revins_chars--;
8511#endif
8512 }
8513 /* if 'whichwrap' set for cursor in insert mode, may move the
8514 * cursor to the next line */
8515 else if (vim_strchr(p_ww, ']') != NULL
8516 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
8517 {
8518 start_arrow(&curwin->w_cursor);
8519 curwin->w_set_curswant = TRUE;
8520 ++curwin->w_cursor.lnum;
8521 curwin->w_cursor.col = 0;
8522 }
8523 else
8524 vim_beep();
8525}
8526
8527 static void
8528ins_s_right()
8529{
8530#ifdef FEAT_FOLDING
8531 if ((fdo_flags & FDO_HOR) && KeyTyped)
8532 foldOpenCursor();
8533#endif
8534 undisplay_dollar();
8535 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
8536 || gchar_cursor() != NUL)
8537 {
8538 start_arrow(&curwin->w_cursor);
8539 (void)fwd_word(1L, FALSE, 0);
8540 curwin->w_set_curswant = TRUE;
8541 }
8542 else
8543 vim_beep();
8544}
8545
8546 static void
8547ins_up(startcol)
8548 int startcol; /* when TRUE move to Insstart.col */
8549{
8550 pos_T tpos;
8551 linenr_T old_topline = curwin->w_topline;
8552#ifdef FEAT_DIFF
8553 int old_topfill = curwin->w_topfill;
8554#endif
8555
8556 undisplay_dollar();
8557 tpos = curwin->w_cursor;
8558 if (cursor_up(1L, TRUE) == OK)
8559 {
8560 if (startcol)
8561 coladvance(getvcol_nolist(&Insstart));
8562 if (old_topline != curwin->w_topline
8563#ifdef FEAT_DIFF
8564 || old_topfill != curwin->w_topfill
8565#endif
8566 )
8567 redraw_later(VALID);
8568 start_arrow(&tpos);
8569#ifdef FEAT_CINDENT
8570 can_cindent = TRUE;
8571#endif
8572 }
8573 else
8574 vim_beep();
8575}
8576
8577 static void
8578ins_pageup()
8579{
8580 pos_T tpos;
8581
8582 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008583
8584#ifdef FEAT_WINDOWS
8585 if (mod_mask & MOD_MASK_CTRL)
8586 {
8587 /* <C-PageUp>: tab page back */
8588 goto_tabpage(-1);
8589 return;
8590 }
8591#endif
8592
Bram Moolenaar071d4272004-06-13 20:20:40 +00008593 tpos = curwin->w_cursor;
8594 if (onepage(BACKWARD, 1L) == OK)
8595 {
8596 start_arrow(&tpos);
8597#ifdef FEAT_CINDENT
8598 can_cindent = TRUE;
8599#endif
8600 }
8601 else
8602 vim_beep();
8603}
8604
8605 static void
8606ins_down(startcol)
8607 int startcol; /* when TRUE move to Insstart.col */
8608{
8609 pos_T tpos;
8610 linenr_T old_topline = curwin->w_topline;
8611#ifdef FEAT_DIFF
8612 int old_topfill = curwin->w_topfill;
8613#endif
8614
8615 undisplay_dollar();
8616 tpos = curwin->w_cursor;
8617 if (cursor_down(1L, TRUE) == OK)
8618 {
8619 if (startcol)
8620 coladvance(getvcol_nolist(&Insstart));
8621 if (old_topline != curwin->w_topline
8622#ifdef FEAT_DIFF
8623 || old_topfill != curwin->w_topfill
8624#endif
8625 )
8626 redraw_later(VALID);
8627 start_arrow(&tpos);
8628#ifdef FEAT_CINDENT
8629 can_cindent = TRUE;
8630#endif
8631 }
8632 else
8633 vim_beep();
8634}
8635
8636 static void
8637ins_pagedown()
8638{
8639 pos_T tpos;
8640
8641 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008642
8643#ifdef FEAT_WINDOWS
8644 if (mod_mask & MOD_MASK_CTRL)
8645 {
8646 /* <C-PageDown>: tab page forward */
8647 goto_tabpage(0);
8648 return;
8649 }
8650#endif
8651
Bram Moolenaar071d4272004-06-13 20:20:40 +00008652 tpos = curwin->w_cursor;
8653 if (onepage(FORWARD, 1L) == OK)
8654 {
8655 start_arrow(&tpos);
8656#ifdef FEAT_CINDENT
8657 can_cindent = TRUE;
8658#endif
8659 }
8660 else
8661 vim_beep();
8662}
8663
8664#ifdef FEAT_DND
8665 static void
8666ins_drop()
8667{
8668 do_put('~', BACKWARD, 1L, PUT_CURSEND);
8669}
8670#endif
8671
8672/*
8673 * Handle TAB in Insert or Replace mode.
8674 * Return TRUE when the TAB needs to be inserted like a normal character.
8675 */
8676 static int
8677ins_tab()
8678{
8679 int ind;
8680 int i;
8681 int temp;
8682
8683 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
8684 Insstart_blank_vcol = get_nolist_virtcol();
8685 if (echeck_abbr(TAB + ABBR_OFF))
8686 return FALSE;
8687
8688 ind = inindent(0);
8689#ifdef FEAT_CINDENT
8690 if (ind)
8691 can_cindent = FALSE;
8692#endif
8693
8694 /*
8695 * When nothing special, insert TAB like a normal character
8696 */
8697 if (!curbuf->b_p_et
8698 && !(p_sta && ind && curbuf->b_p_ts != curbuf->b_p_sw)
8699 && curbuf->b_p_sts == 0)
8700 return TRUE;
8701
8702 if (stop_arrow() == FAIL)
8703 return TRUE;
8704
8705 did_ai = FALSE;
8706#ifdef FEAT_SMARTINDENT
8707 did_si = FALSE;
8708 can_si = FALSE;
8709 can_si_back = FALSE;
8710#endif
8711 AppendToRedobuff((char_u *)"\t");
8712
8713 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
8714 temp = (int)curbuf->b_p_sw;
8715 else if (curbuf->b_p_sts > 0) /* use 'softtabstop' when set */
8716 temp = (int)curbuf->b_p_sts;
8717 else /* otherwise use 'tabstop' */
8718 temp = (int)curbuf->b_p_ts;
8719 temp -= get_nolist_virtcol() % temp;
8720
8721 /*
8722 * Insert the first space with ins_char(). It will delete one char in
8723 * replace mode. Insert the rest with ins_str(); it will not delete any
8724 * chars. For VREPLACE mode, we use ins_char() for all characters.
8725 */
8726 ins_char(' ');
8727 while (--temp > 0)
8728 {
8729#ifdef FEAT_VREPLACE
8730 if (State & VREPLACE_FLAG)
8731 ins_char(' ');
8732 else
8733#endif
8734 {
8735 ins_str((char_u *)" ");
8736 if (State & REPLACE_FLAG) /* no char replaced */
8737 replace_push(NUL);
8738 }
8739 }
8740
8741 /*
8742 * When 'expandtab' not set: Replace spaces by TABs where possible.
8743 */
8744 if (!curbuf->b_p_et && (curbuf->b_p_sts || (p_sta && ind)))
8745 {
8746 char_u *ptr;
8747#ifdef FEAT_VREPLACE
8748 char_u *saved_line = NULL; /* init for GCC */
8749 pos_T pos;
8750#endif
8751 pos_T fpos;
8752 pos_T *cursor;
8753 colnr_T want_vcol, vcol;
8754 int change_col = -1;
8755 int save_list = curwin->w_p_list;
8756
8757 /*
8758 * Get the current line. For VREPLACE mode, don't make real changes
8759 * yet, just work on a copy of the line.
8760 */
8761#ifdef FEAT_VREPLACE
8762 if (State & VREPLACE_FLAG)
8763 {
8764 pos = curwin->w_cursor;
8765 cursor = &pos;
8766 saved_line = vim_strsave(ml_get_curline());
8767 if (saved_line == NULL)
8768 return FALSE;
8769 ptr = saved_line + pos.col;
8770 }
8771 else
8772#endif
8773 {
8774 ptr = ml_get_cursor();
8775 cursor = &curwin->w_cursor;
8776 }
8777
8778 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
8779 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8780 curwin->w_p_list = FALSE;
8781
8782 /* Find first white before the cursor */
8783 fpos = curwin->w_cursor;
8784 while (fpos.col > 0 && vim_iswhite(ptr[-1]))
8785 {
8786 --fpos.col;
8787 --ptr;
8788 }
8789
8790 /* In Replace mode, don't change characters before the insert point. */
8791 if ((State & REPLACE_FLAG)
8792 && fpos.lnum == Insstart.lnum
8793 && fpos.col < Insstart.col)
8794 {
8795 ptr += Insstart.col - fpos.col;
8796 fpos.col = Insstart.col;
8797 }
8798
8799 /* compute virtual column numbers of first white and cursor */
8800 getvcol(curwin, &fpos, &vcol, NULL, NULL);
8801 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
8802
8803 /* Use as many TABs as possible. Beware of 'showbreak' and
8804 * 'linebreak' adding extra virtual columns. */
8805 while (vim_iswhite(*ptr))
8806 {
8807 i = lbr_chartabsize((char_u *)"\t", vcol);
8808 if (vcol + i > want_vcol)
8809 break;
8810 if (*ptr != TAB)
8811 {
8812 *ptr = TAB;
8813 if (change_col < 0)
8814 {
8815 change_col = fpos.col; /* Column of first change */
8816 /* May have to adjust Insstart */
8817 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
8818 Insstart.col = fpos.col;
8819 }
8820 }
8821 ++fpos.col;
8822 ++ptr;
8823 vcol += i;
8824 }
8825
8826 if (change_col >= 0)
8827 {
8828 int repl_off = 0;
8829
8830 /* Skip over the spaces we need. */
8831 while (vcol < want_vcol && *ptr == ' ')
8832 {
8833 vcol += lbr_chartabsize(ptr, vcol);
8834 ++ptr;
8835 ++repl_off;
8836 }
8837 if (vcol > want_vcol)
8838 {
8839 /* Must have a char with 'showbreak' just before it. */
8840 --ptr;
8841 --repl_off;
8842 }
8843 fpos.col += repl_off;
8844
8845 /* Delete following spaces. */
8846 i = cursor->col - fpos.col;
8847 if (i > 0)
8848 {
8849 mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
8850 /* correct replace stack. */
8851 if ((State & REPLACE_FLAG)
8852#ifdef FEAT_VREPLACE
8853 && !(State & VREPLACE_FLAG)
8854#endif
8855 )
8856 for (temp = i; --temp >= 0; )
8857 replace_join(repl_off);
8858 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00008859#ifdef FEAT_NETBEANS_INTG
8860 if (usingNetbeans)
8861 {
8862 netbeans_removed(curbuf, fpos.lnum, cursor->col,
8863 (long)(i + 1));
8864 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
8865 (char_u *)"\t", 1);
8866 }
8867#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008868 cursor->col -= i;
8869
8870#ifdef FEAT_VREPLACE
8871 /*
8872 * In VREPLACE mode, we haven't changed anything yet. Do it now by
8873 * backspacing over the changed spacing and then inserting the new
8874 * spacing.
8875 */
8876 if (State & VREPLACE_FLAG)
8877 {
8878 /* Backspace from real cursor to change_col */
8879 backspace_until_column(change_col);
8880
8881 /* Insert each char in saved_line from changed_col to
8882 * ptr-cursor */
8883 ins_bytes_len(saved_line + change_col,
8884 cursor->col - change_col);
8885 }
8886#endif
8887 }
8888
8889#ifdef FEAT_VREPLACE
8890 if (State & VREPLACE_FLAG)
8891 vim_free(saved_line);
8892#endif
8893 curwin->w_p_list = save_list;
8894 }
8895
8896 return FALSE;
8897}
8898
8899/*
8900 * Handle CR or NL in insert mode.
8901 * Return TRUE when out of memory or can't undo.
8902 */
8903 static int
8904ins_eol(c)
8905 int c;
8906{
8907 int i;
8908
8909 if (echeck_abbr(c + ABBR_OFF))
8910 return FALSE;
8911 if (stop_arrow() == FAIL)
8912 return TRUE;
8913 undisplay_dollar();
8914
8915 /*
8916 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
8917 * character under the cursor. Only push a NUL on the replace stack,
8918 * nothing to put back when the NL is deleted.
8919 */
8920 if ((State & REPLACE_FLAG)
8921#ifdef FEAT_VREPLACE
8922 && !(State & VREPLACE_FLAG)
8923#endif
8924 )
8925 replace_push(NUL);
8926
8927 /*
8928 * In VREPLACE mode, a NL replaces the rest of the line, and starts
8929 * replacing the next line, so we push all of the characters left on the
8930 * line onto the replace stack. This is not done here though, it is done
8931 * in open_line().
8932 */
8933
8934#ifdef FEAT_RIGHTLEFT
8935# ifdef FEAT_FKMAP
8936 if (p_altkeymap && p_fkmap)
8937 fkmap(NL);
8938# endif
8939 /* NL in reverse insert will always start in the end of
8940 * current line. */
8941 if (revins_on)
8942 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
8943#endif
8944
8945 AppendToRedobuff(NL_STR);
8946 i = open_line(FORWARD,
8947#ifdef FEAT_COMMENTS
8948 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
8949#endif
8950 0, old_indent);
8951 old_indent = 0;
8952#ifdef FEAT_CINDENT
8953 can_cindent = TRUE;
8954#endif
8955
8956 return (!i);
8957}
8958
8959#ifdef FEAT_DIGRAPHS
8960/*
8961 * Handle digraph in insert mode.
8962 * Returns character still to be inserted, or NUL when nothing remaining to be
8963 * done.
8964 */
8965 static int
8966ins_digraph()
8967{
8968 int c;
8969 int cc;
8970
8971 pc_status = PC_STATUS_UNSET;
8972 if (redrawing() && !char_avail())
8973 {
8974 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00008975 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008976
8977 edit_putchar('?', TRUE);
8978#ifdef FEAT_CMDL_INFO
8979 add_to_showcmd_c(Ctrl_K);
8980#endif
8981 }
8982
8983#ifdef USE_ON_FLY_SCROLL
8984 dont_scroll = TRUE; /* disallow scrolling here */
8985#endif
8986
8987 /* don't map the digraph chars. This also prevents the
8988 * mode message to be deleted when ESC is hit */
8989 ++no_mapping;
8990 ++allow_keys;
8991 c = safe_vgetc();
8992 --no_mapping;
8993 --allow_keys;
8994 if (IS_SPECIAL(c) || mod_mask) /* special key */
8995 {
8996#ifdef FEAT_CMDL_INFO
8997 clear_showcmd();
8998#endif
8999 insert_special(c, TRUE, FALSE);
9000 return NUL;
9001 }
9002 if (c != ESC)
9003 {
9004 if (redrawing() && !char_avail())
9005 {
9006 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00009007 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009008
9009 if (char2cells(c) == 1)
9010 {
9011 /* first remove the '?', otherwise it's restored when typing
9012 * an ESC next */
9013 edit_unputchar();
Bram Moolenaar754b5602006-02-09 23:53:20 +00009014 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009015 edit_putchar(c, TRUE);
9016 }
9017#ifdef FEAT_CMDL_INFO
9018 add_to_showcmd_c(c);
9019#endif
9020 }
9021 ++no_mapping;
9022 ++allow_keys;
9023 cc = safe_vgetc();
9024 --no_mapping;
9025 --allow_keys;
9026 if (cc != ESC)
9027 {
9028 AppendToRedobuff((char_u *)CTRL_V_STR);
9029 c = getdigraph(c, cc, TRUE);
9030#ifdef FEAT_CMDL_INFO
9031 clear_showcmd();
9032#endif
9033 return c;
9034 }
9035 }
9036 edit_unputchar();
9037#ifdef FEAT_CMDL_INFO
9038 clear_showcmd();
9039#endif
9040 return NUL;
9041}
9042#endif
9043
9044/*
9045 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
9046 * Returns the char to be inserted, or NUL if none found.
9047 */
9048 static int
9049ins_copychar(lnum)
9050 linenr_T lnum;
9051{
9052 int c;
9053 int temp;
9054 char_u *ptr, *prev_ptr;
9055
9056 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
9057 {
9058 vim_beep();
9059 return NUL;
9060 }
9061
9062 /* try to advance to the cursor column */
9063 temp = 0;
9064 ptr = ml_get(lnum);
9065 prev_ptr = ptr;
9066 validate_virtcol();
9067 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
9068 {
9069 prev_ptr = ptr;
9070 temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
9071 }
9072 if ((colnr_T)temp > curwin->w_virtcol)
9073 ptr = prev_ptr;
9074
9075#ifdef FEAT_MBYTE
9076 c = (*mb_ptr2char)(ptr);
9077#else
9078 c = *ptr;
9079#endif
9080 if (c == NUL)
9081 vim_beep();
9082 return c;
9083}
9084
Bram Moolenaar4be06f92005-07-29 22:36:03 +00009085/*
9086 * CTRL-Y or CTRL-E typed in Insert mode.
9087 */
9088 static int
9089ins_ctrl_ey(tc)
9090 int tc;
9091{
9092 int c = tc;
9093
9094#ifdef FEAT_INS_EXPAND
9095 if (ctrl_x_mode == CTRL_X_SCROLL)
9096 {
9097 if (c == Ctrl_Y)
9098 scrolldown_clamp();
9099 else
9100 scrollup_clamp();
9101 redraw_later(VALID);
9102 }
9103 else
9104#endif
9105 {
9106 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
9107 if (c != NUL)
9108 {
9109 long tw_save;
9110
9111 /* The character must be taken literally, insert like it
9112 * was typed after a CTRL-V, and pretend 'textwidth'
9113 * wasn't set. Digits, 'o' and 'x' are special after a
9114 * CTRL-V, don't use it for these. */
9115 if (c < 256 && !isalnum(c))
9116 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
9117 tw_save = curbuf->b_p_tw;
9118 curbuf->b_p_tw = -1;
9119 insert_special(c, TRUE, FALSE);
9120 curbuf->b_p_tw = tw_save;
9121#ifdef FEAT_RIGHTLEFT
9122 revins_chars++;
9123 revins_legal++;
9124#endif
9125 c = Ctrl_V; /* pretend CTRL-V is last character */
9126 auto_format(FALSE, TRUE);
9127 }
9128 }
9129 return c;
9130}
9131
Bram Moolenaar071d4272004-06-13 20:20:40 +00009132#ifdef FEAT_SMARTINDENT
9133/*
9134 * Try to do some very smart auto-indenting.
9135 * Used when inserting a "normal" character.
9136 */
9137 static void
9138ins_try_si(c)
9139 int c;
9140{
9141 pos_T *pos, old_pos;
9142 char_u *ptr;
9143 int i;
9144 int temp;
9145
9146 /*
9147 * do some very smart indenting when entering '{' or '}'
9148 */
9149 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
9150 {
9151 /*
9152 * for '}' set indent equal to indent of line containing matching '{'
9153 */
9154 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
9155 {
9156 old_pos = curwin->w_cursor;
9157 /*
9158 * If the matching '{' has a ')' immediately before it (ignoring
9159 * white-space), then line up with the start of the line
9160 * containing the matching '(' if there is one. This handles the
9161 * case where an "if (..\n..) {" statement continues over multiple
9162 * lines -- webb
9163 */
9164 ptr = ml_get(pos->lnum);
9165 i = pos->col;
9166 if (i > 0) /* skip blanks before '{' */
9167 while (--i > 0 && vim_iswhite(ptr[i]))
9168 ;
9169 curwin->w_cursor.lnum = pos->lnum;
9170 curwin->w_cursor.col = i;
9171 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
9172 curwin->w_cursor = *pos;
9173 i = get_indent();
9174 curwin->w_cursor = old_pos;
9175#ifdef FEAT_VREPLACE
9176 if (State & VREPLACE_FLAG)
9177 change_indent(INDENT_SET, i, FALSE, NUL);
9178 else
9179#endif
9180 (void)set_indent(i, SIN_CHANGED);
9181 }
9182 else if (curwin->w_cursor.col > 0)
9183 {
9184 /*
9185 * when inserting '{' after "O" reduce indent, but not
9186 * more than indent of previous line
9187 */
9188 temp = TRUE;
9189 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
9190 {
9191 old_pos = curwin->w_cursor;
9192 i = get_indent();
9193 while (curwin->w_cursor.lnum > 1)
9194 {
9195 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
9196
9197 /* ignore empty lines and lines starting with '#'. */
9198 if (*ptr != '#' && *ptr != NUL)
9199 break;
9200 }
9201 if (get_indent() >= i)
9202 temp = FALSE;
9203 curwin->w_cursor = old_pos;
9204 }
9205 if (temp)
9206 shift_line(TRUE, FALSE, 1);
9207 }
9208 }
9209
9210 /*
9211 * set indent of '#' always to 0
9212 */
9213 if (curwin->w_cursor.col > 0 && can_si && c == '#')
9214 {
9215 /* remember current indent for next line */
9216 old_indent = get_indent();
9217 (void)set_indent(0, SIN_CHANGED);
9218 }
9219
9220 /* Adjust ai_col, the char at this position can be deleted. */
9221 if (ai_col > curwin->w_cursor.col)
9222 ai_col = curwin->w_cursor.col;
9223}
9224#endif
9225
9226/*
9227 * Get the value that w_virtcol would have when 'list' is off.
9228 * Unless 'cpo' contains the 'L' flag.
9229 */
9230 static colnr_T
9231get_nolist_virtcol()
9232{
9233 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
9234 return getvcol_nolist(&curwin->w_cursor);
9235 validate_virtcol();
9236 return curwin->w_virtcol;
9237}