blob: 30d4c3bfa9c8d5039e5c1c4ee9466f280d3813cd [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
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000338 /* Don't allow recursive insert mode when busy with completion. */
339 if (compl_started || pum_visible())
340 {
341 EMSG(_(e_secure));
342 return FALSE;
343 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 ins_compl_clear(); /* clear stuff for CTRL-X mode */
345#endif
346
Bram Moolenaar843ee412004-06-30 16:16:41 +0000347#ifdef FEAT_AUTOCMD
348 /*
349 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
350 */
351 if (cmdchar != 'r' && cmdchar != 'v')
352 {
Bram Moolenaar1e015462005-09-25 22:16:38 +0000353# ifdef FEAT_EVAL
Bram Moolenaar843ee412004-06-30 16:16:41 +0000354 if (cmdchar == 'R')
355 ptr = (char_u *)"r";
356 else if (cmdchar == 'V')
357 ptr = (char_u *)"v";
358 else
359 ptr = (char_u *)"i";
360 set_vim_var_string(VV_INSERTMODE, ptr, 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +0000361# endif
Bram Moolenaar843ee412004-06-30 16:16:41 +0000362 apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);
363 }
364#endif
365
Bram Moolenaar071d4272004-06-13 20:20:40 +0000366#ifdef FEAT_MOUSE
367 /*
368 * When doing a paste with the middle mouse button, Insstart is set to
369 * where the paste started.
370 */
371 if (where_paste_started.lnum != 0)
372 Insstart = where_paste_started;
373 else
374#endif
375 {
376 Insstart = curwin->w_cursor;
377 if (startln)
378 Insstart.col = 0;
379 }
380 Insstart_textlen = linetabsize(ml_get_curline());
381 Insstart_blank_vcol = MAXCOL;
382 if (!did_ai)
383 ai_col = 0;
384
385 if (cmdchar != NUL && restart_edit == 0)
386 {
387 ResetRedobuff();
388 AppendNumberToRedobuff(count);
389#ifdef FEAT_VREPLACE
390 if (cmdchar == 'V' || cmdchar == 'v')
391 {
392 /* "gR" or "gr" command */
393 AppendCharToRedobuff('g');
394 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
395 }
396 else
397#endif
398 {
399 AppendCharToRedobuff(cmdchar);
400 if (cmdchar == 'g') /* "gI" command */
401 AppendCharToRedobuff('I');
402 else if (cmdchar == 'r') /* "r<CR>" command */
403 count = 1; /* insert only one <CR> */
404 }
405 }
406
407 if (cmdchar == 'R')
408 {
409#ifdef FEAT_FKMAP
410 if (p_fkmap && p_ri)
411 {
412 beep_flush();
413 EMSG(farsi_text_3); /* encoded in Farsi */
414 State = INSERT;
415 }
416 else
417#endif
418 State = REPLACE;
419 }
420#ifdef FEAT_VREPLACE
421 else if (cmdchar == 'V' || cmdchar == 'v')
422 {
423 State = VREPLACE;
424 replaceState = VREPLACE;
425 orig_line_count = curbuf->b_ml.ml_line_count;
426 vr_lines_changed = 1;
427 }
428#endif
429 else
430 State = INSERT;
431
432 stop_insert_mode = FALSE;
433
434 /*
435 * Need to recompute the cursor position, it might move when the cursor is
436 * on a TAB or special character.
437 */
438 curs_columns(TRUE);
439
440 /*
441 * Enable langmap or IME, indicated by 'iminsert'.
442 * Note that IME may enabled/disabled without us noticing here, thus the
443 * 'iminsert' value may not reflect what is actually used. It is updated
444 * when hitting <Esc>.
445 */
446 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
447 State |= LANGMAP;
448#ifdef USE_IM_CONTROL
449 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
450#endif
451
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452#ifdef FEAT_MOUSE
453 setmouse();
454#endif
455#ifdef FEAT_CMDL_INFO
456 clear_showcmd();
457#endif
458#ifdef FEAT_RIGHTLEFT
459 /* there is no reverse replace mode */
460 revins_on = (State == INSERT && p_ri);
461 if (revins_on)
462 undisplay_dollar();
463 revins_chars = 0;
464 revins_legal = 0;
465 revins_scol = -1;
466#endif
467
468 /*
469 * Handle restarting Insert mode.
470 * Don't do this for "CTRL-O ." (repeat an insert): we get here with
471 * restart_edit non-zero, and something in the stuff buffer.
472 */
473 if (restart_edit != 0 && stuff_empty())
474 {
475#ifdef FEAT_MOUSE
476 /*
477 * After a paste we consider text typed to be part of the insert for
478 * the pasted text. You can backspace over the pasted text too.
479 */
480 if (where_paste_started.lnum)
481 arrow_used = FALSE;
482 else
483#endif
484 arrow_used = TRUE;
485 restart_edit = 0;
486
487 /*
488 * If the cursor was after the end-of-line before the CTRL-O and it is
489 * now at the end-of-line, put it after the end-of-line (this is not
490 * correct in very rare cases).
491 * Also do this if curswant is greater than the current virtual
492 * column. Eg after "^O$" or "^O80|".
493 */
494 validate_virtcol();
495 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000496 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000497 || curwin->w_curswant > curwin->w_virtcol)
498 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
499 {
500 if (ptr[1] == NUL)
501 ++curwin->w_cursor.col;
502#ifdef FEAT_MBYTE
503 else if (has_mbyte)
504 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000505 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 if (ptr[i] == NUL)
507 curwin->w_cursor.col += i;
508 }
509#endif
510 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000511 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 }
513 else
514 arrow_used = FALSE;
515
516 /* we are in insert mode now, don't need to start it anymore */
517 need_start_insertmode = FALSE;
518
519 /* Need to save the line for undo before inserting the first char. */
520 ins_need_undo = TRUE;
521
522#ifdef FEAT_MOUSE
523 where_paste_started.lnum = 0;
524#endif
525#ifdef FEAT_CINDENT
526 can_cindent = TRUE;
527#endif
528#ifdef FEAT_FOLDING
529 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
530 * restarting. */
531 if (!p_im && did_restart_edit == 0)
532 foldOpenCursor();
533#endif
534
535 /*
536 * If 'showmode' is set, show the current (insert/replace/..) mode.
537 * A warning message for changing a readonly file is given here, before
538 * actually changing anything. It's put after the mode, if any.
539 */
540 i = 0;
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000541 if (p_smd && msg_silent == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 i = showmode();
543
544 if (!p_im && did_restart_edit == 0)
545 change_warning(i + 1);
546
547#ifdef CURSOR_SHAPE
548 ui_cursor_shape(); /* may show different cursor shape */
549#endif
550#ifdef FEAT_DIGRAPHS
551 do_digraph(-1); /* clear digraphs */
552#endif
553
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000554 /*
555 * Get the current length of the redo buffer, those characters have to be
556 * skipped if we want to get to the inserted characters.
557 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 ptr = get_inserted();
559 if (ptr == NULL)
560 new_insert_skip = 0;
561 else
562 {
563 new_insert_skip = (int)STRLEN(ptr);
564 vim_free(ptr);
565 }
566
567 old_indent = 0;
568
569 /*
570 * Main loop in Insert mode: repeat until Insert mode is left.
571 */
572 for (;;)
573 {
574#ifdef FEAT_RIGHTLEFT
575 if (!revins_legal)
576 revins_scol = -1; /* reset on illegal motions */
577 else
578 revins_legal = 0;
579#endif
580 if (arrow_used) /* don't repeat insert when arrow key used */
581 count = 0;
582
583 if (stop_insert_mode)
584 {
585 /* ":stopinsert" used or 'insertmode' reset */
586 count = 0;
587 goto doESCkey;
588 }
589
590 /* set curwin->w_curswant for next K_DOWN or K_UP */
591 if (!arrow_used)
592 curwin->w_set_curswant = TRUE;
593
594 /* If there is no typeahead may check for timestamps (e.g., for when a
595 * menu invoked a shell command). */
596 if (stuff_empty())
597 {
598 did_check_timestamps = FALSE;
599 if (need_check_timestamps)
600 check_timestamps(FALSE);
601 }
602
603 /*
604 * When emsg() was called msg_scroll will have been set.
605 */
606 msg_scroll = FALSE;
607
608#ifdef FEAT_GUI
609 /* When 'mousefocus' is set a mouse movement may have taken us to
610 * another window. "need_mouse_correct" may then be set because of an
611 * autocommand. */
612 if (need_mouse_correct)
613 gui_mouse_correct();
614#endif
615
616#ifdef FEAT_FOLDING
617 /* Open fold at the cursor line, according to 'foldopen'. */
618 if (fdo_flags & FDO_INSERT)
619 foldOpenCursor();
620 /* Close folds where the cursor isn't, according to 'foldclose' */
621 if (!char_avail())
622 foldCheckClose();
623#endif
624
625 /*
626 * If we inserted a character at the last position of the last line in
627 * the window, scroll the window one line up. This avoids an extra
628 * redraw.
629 * This is detected when the cursor column is smaller after inserting
630 * something.
631 * Don't do this when the topline changed already, it has
632 * already been adjusted (by insertchar() calling open_line())).
633 */
634 if (curbuf->b_mod_set
635 && curwin->w_p_wrap
636 && !did_backspace
637 && curwin->w_topline == old_topline
638#ifdef FEAT_DIFF
639 && curwin->w_topfill == old_topfill
640#endif
641 )
642 {
643 mincol = curwin->w_wcol;
644 validate_cursor_col();
645
646 if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts
647 && curwin->w_wrow == W_WINROW(curwin)
648 + curwin->w_height - 1 - p_so
649 && (curwin->w_cursor.lnum != curwin->w_topline
650#ifdef FEAT_DIFF
651 || curwin->w_topfill > 0
652#endif
653 ))
654 {
655#ifdef FEAT_DIFF
656 if (curwin->w_topfill > 0)
657 --curwin->w_topfill;
658 else
659#endif
660#ifdef FEAT_FOLDING
661 if (hasFolding(curwin->w_topline, NULL, &old_topline))
662 set_topline(curwin, old_topline + 1);
663 else
664#endif
665 set_topline(curwin, curwin->w_topline + 1);
666 }
667 }
668
669 /* May need to adjust w_topline to show the cursor. */
670 update_topline();
671
672 did_backspace = FALSE;
673
674 validate_cursor(); /* may set must_redraw */
675
676 /*
677 * Redraw the display when no characters are waiting.
678 * Also shows mode, ruler and positions cursor.
679 */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000680 ins_redraw(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681
682#ifdef FEAT_SCROLLBIND
683 if (curwin->w_p_scb)
684 do_check_scrollbind(TRUE);
685#endif
686
687 update_curswant();
688 old_topline = curwin->w_topline;
689#ifdef FEAT_DIFF
690 old_topfill = curwin->w_topfill;
691#endif
692
693#ifdef USE_ON_FLY_SCROLL
694 dont_scroll = FALSE; /* allow scrolling here */
695#endif
696
697 /*
698 * Get a character for Insert mode.
699 */
700 lastc = c; /* remember previous char for CTRL-D */
701 c = safe_vgetc();
702
703#ifdef FEAT_RIGHTLEFT
704 if (p_hkmap && KeyTyped)
705 c = hkmap(c); /* Hebrew mode mapping */
706#endif
707#ifdef FEAT_FKMAP
708 if (p_fkmap && KeyTyped)
709 c = fkmap(c); /* Farsi mode mapping */
710#endif
711
712#ifdef FEAT_INS_EXPAND
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000713 /*
714 * Special handling of keys while the popup menu is visible or wanted
715 * and the cursor is still in the completed word.
716 */
717 if (compl_started && pum_wanted() && curwin->w_cursor.col >= compl_col)
Bram Moolenaara6557602006-02-04 22:43:20 +0000718 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000719 /* BS: Delete one character from "compl_leader". */
720 if ((c == K_BS || c == Ctrl_H)
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000721 && curwin->w_cursor.col > compl_col
722 && (c = ins_compl_bs()) == NUL)
Bram Moolenaara6557602006-02-04 22:43:20 +0000723 continue;
724
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000725 /* When no match was selected or it was edited. */
726 if (!compl_used_match)
Bram Moolenaara6557602006-02-04 22:43:20 +0000727 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000728 /* CTRL-L: Add one character from the current match to
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000729 * "compl_leader". Except when at the original match and
730 * there is nothing to add, CTRL-L works like CTRL-P then. */
731 if (c == Ctrl_L
732 && (ctrl_x_mode != CTRL_X_WHOLE_LINE
733 || STRLEN(compl_shown_match->cp_str)
734 > curwin->w_cursor.col - compl_col))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000735 {
736 ins_compl_addfrommatch();
737 continue;
738 }
739
Bram Moolenaardf1bdc92006-02-23 21:32:16 +0000740 /* A printable, non-white character: Add to "compl_leader". */
741 if (vim_isprintc(c) && !vim_iswhite(c))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000742 {
743 ins_compl_addleader(c);
744 continue;
745 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000746
Bram Moolenaar779b74b2006-04-10 14:55:34 +0000747 /* Pressing CTRL-Y selects the current match. Shen
748 * compl_enter_selects is set the Enter key does the same. */
749 if (c == Ctrl_Y || (compl_enter_selects
750 && (c == CAR || c == K_KENTER || c == NL)))
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000751 {
752 ins_compl_delete();
753 ins_compl_insert();
754 }
Bram Moolenaara6557602006-02-04 22:43:20 +0000755 }
756 }
757
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
759 * it does fix up the text when finishing completion. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000760 compl_get_longest = FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +0000761 if (c != K_IGNORE && ins_compl_prep(c))
762 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763#endif
764
Bram Moolenaar488c6512005-08-11 20:09:58 +0000765 /* CTRL-\ CTRL-N goes to Normal mode,
766 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
767 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 if (c == Ctrl_BSL)
769 {
770 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000771 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 ++no_mapping;
773 ++allow_keys;
774 c = safe_vgetc();
775 --no_mapping;
776 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000777 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000779 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 vungetc(c);
781 c = Ctrl_BSL;
782 }
783 else if (c == Ctrl_G && p_im)
784 continue;
785 else
786 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000787 if (c == Ctrl_O)
788 {
789 ins_ctrl_o();
790 ins_at_eol = FALSE; /* cursor keeps its column */
791 nomove = TRUE;
792 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 count = 0;
794 goto doESCkey;
795 }
796 }
797
798#ifdef FEAT_DIGRAPHS
799 c = do_digraph(c);
800#endif
801
802#ifdef FEAT_INS_EXPAND
803 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
804 goto docomplete;
805#endif
806 if (c == Ctrl_V || c == Ctrl_Q)
807 {
808 ins_ctrl_v();
809 c = Ctrl_V; /* pretend CTRL-V is last typed character */
810 continue;
811 }
812
813#ifdef FEAT_CINDENT
814 if (cindent_on()
815# ifdef FEAT_INS_EXPAND
816 && ctrl_x_mode == 0
817# endif
818 )
819 {
820 /* A key name preceded by a bang means this key is not to be
821 * inserted. Skip ahead to the re-indenting below.
822 * A key name preceded by a star means that indenting has to be
823 * done before inserting the key. */
824 line_is_white = inindent(0);
825 if (in_cinkeys(c, '!', line_is_white))
826 goto force_cindent;
827 if (can_cindent && in_cinkeys(c, '*', line_is_white)
828 && stop_arrow() == OK)
829 do_c_expr_indent();
830 }
831#endif
832
833#ifdef FEAT_RIGHTLEFT
834 if (curwin->w_p_rl)
835 switch (c)
836 {
837 case K_LEFT: c = K_RIGHT; break;
838 case K_S_LEFT: c = K_S_RIGHT; break;
839 case K_C_LEFT: c = K_C_RIGHT; break;
840 case K_RIGHT: c = K_LEFT; break;
841 case K_S_RIGHT: c = K_S_LEFT; break;
842 case K_C_RIGHT: c = K_C_LEFT; break;
843 }
844#endif
845
846#ifdef FEAT_VISUAL
847 /*
848 * If 'keymodel' contains "startsel", may start selection. If it
849 * does, a CTRL-O and c will be stuffed, we need to get these
850 * characters.
851 */
852 if (ins_start_select(c))
853 continue;
854#endif
855
856 /*
857 * The big switch to handle a character in insert mode.
858 */
859 switch (c)
860 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000861 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 if (echeck_abbr(ESC + ABBR_OFF))
863 break;
864 /*FALLTHROUGH*/
865
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000866 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867#ifdef FEAT_CMDWIN
868 if (c == Ctrl_C && cmdwin_type != 0)
869 {
870 /* Close the cmdline window. */
871 cmdwin_result = K_IGNORE;
872 got_int = FALSE; /* don't stop executing autocommands et al. */
873 goto doESCkey;
874 }
875#endif
876
877#ifdef UNIX
878do_intr:
879#endif
880 /* when 'insertmode' set, and not halfway a mapping, don't leave
881 * Insert mode */
882 if (goto_im())
883 {
884 if (got_int)
885 {
886 (void)vgetc(); /* flush all buffers */
887 got_int = FALSE;
888 }
889 else
890 vim_beep();
891 break;
892 }
893doESCkey:
894 /*
895 * This is the ONLY return from edit()!
896 */
897 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
898 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000899 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 o_lnum = curwin->w_cursor.lnum;
901
Bram Moolenaar488c6512005-08-11 20:09:58 +0000902 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000903 {
904#ifdef FEAT_AUTOCMD
905 if (cmdchar != 'r' && cmdchar != 'v')
906 apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL,
907 FALSE, curbuf);
908#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000910 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 continue;
912
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000913 case Ctrl_Z: /* suspend when 'insertmode' set */
914 if (!p_im)
915 goto normalchar; /* insert CTRL-Z as normal char */
916 stuffReadbuff((char_u *)":st\r");
917 c = Ctrl_O;
918 /*FALLTHROUGH*/
919
920 case Ctrl_O: /* execute one command */
Bram Moolenaare344bea2005-09-01 20:46:49 +0000921#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000922 if (ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000923 goto docomplete;
924#endif
925 if (echeck_abbr(Ctrl_O + ABBR_OFF))
926 break;
927 ins_ctrl_o();
928 count = 0;
929 goto doESCkey;
930
Bram Moolenaar572cb562005-08-05 21:35:02 +0000931 case K_INS: /* toggle insert/replace mode */
932 case K_KINS:
933 ins_insert(replaceState);
934 break;
935
936 case K_SELECT: /* end of Select mode mapping - ignore */
937 break;
938
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000939#ifdef FEAT_SNIFF
940 case K_SNIFF: /* Sniff command received */
941 stuffcharReadbuff(K_SNIFF);
942 goto doESCkey;
943#endif
944
945 case K_HELP: /* Help key works like <ESC> <Help> */
946 case K_F1:
947 case K_XF1:
948 stuffcharReadbuff(K_HELP);
949 if (p_im)
950 need_start_insertmode = TRUE;
951 goto doESCkey;
952
953#ifdef FEAT_NETBEANS_INTG
954 case K_F21: /* NetBeans command */
955 ++no_mapping; /* don't map the next key hits */
956 i = safe_vgetc();
957 --no_mapping;
958 netbeans_keycommand(i);
959 break;
960#endif
961
962 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963 case NUL:
964 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000965 /* For ^@ the trailing ESC will end the insert, unless there is an
966 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
968 && c != Ctrl_A && !p_im)
969 goto doESCkey; /* quit insert mode */
970 inserted_space = FALSE;
971 break;
972
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000973 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 ins_reg();
975 auto_format(FALSE, TRUE);
976 inserted_space = FALSE;
977 break;
978
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000979 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 ins_ctrl_g();
981 break;
982
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000983 case Ctrl_HAT: /* switch input mode and/or langmap */
984 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985 break;
986
987#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000988 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989 if (!p_ari)
990 goto normalchar;
991 ins_ctrl_();
992 break;
993#endif
994
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000995 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
997 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
998 goto docomplete;
999#endif
1000 /* FALLTHROUGH */
1001
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001002 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001003# ifdef FEAT_INS_EXPAND
1004 if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
1005 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001006 if (has_compl_option(FALSE))
1007 goto docomplete;
1008 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 }
1010# endif
1011 ins_shift(c, lastc);
1012 auto_format(FALSE, TRUE);
1013 inserted_space = FALSE;
1014 break;
1015
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001016 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 case K_KDEL:
1018 ins_del();
1019 auto_format(FALSE, TRUE);
1020 break;
1021
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001022 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 case Ctrl_H:
1024 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
1025 auto_format(FALSE, TRUE);
1026 break;
1027
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001028 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
1030 auto_format(FALSE, TRUE);
1031 break;
1032
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001033 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001034# ifdef FEAT_COMPL_FUNC
1035 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001036 if (ctrl_x_mode == CTRL_X_FUNCTION)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001037 goto docomplete;
1038# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
1040 auto_format(FALSE, TRUE);
1041 inserted_space = FALSE;
1042 break;
1043
1044#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001045 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 case K_LEFTMOUSE_NM:
1047 case K_LEFTDRAG:
1048 case K_LEFTRELEASE:
1049 case K_LEFTRELEASE_NM:
1050 case K_MIDDLEMOUSE:
1051 case K_MIDDLEDRAG:
1052 case K_MIDDLERELEASE:
1053 case K_RIGHTMOUSE:
1054 case K_RIGHTDRAG:
1055 case K_RIGHTRELEASE:
1056 case K_X1MOUSE:
1057 case K_X1DRAG:
1058 case K_X1RELEASE:
1059 case K_X2MOUSE:
1060 case K_X2DRAG:
1061 case K_X2RELEASE:
1062 ins_mouse(c);
1063 break;
1064
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001065 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 ins_mousescroll(FALSE);
1067 break;
1068
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001069 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 ins_mousescroll(TRUE);
1071 break;
1072#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +00001073#ifdef FEAT_GUI_TABLINE
1074 case K_TABLINE:
1075 case K_TABMENU:
1076 ins_tabline(c);
1077 break;
1078#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001080 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 break;
1082
Bram Moolenaar754b5602006-02-09 23:53:20 +00001083#ifdef FEAT_AUTOCMD
1084 case K_CURSORHOLD: /* Didn't type something for a while. */
1085 apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf);
1086 did_cursorhold = TRUE;
1087 break;
1088#endif
1089
Bram Moolenaar4770d092006-01-12 23:22:24 +00001090#ifdef FEAT_GUI_W32
1091 /* On Win32 ignore <M-F4>, we get it when closing the window was
1092 * cancelled. */
1093 case K_F4:
1094 if (mod_mask != MOD_MASK_ALT)
1095 goto normalchar;
1096 break;
1097#endif
1098
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099#ifdef FEAT_GUI
1100 case K_VER_SCROLLBAR:
1101 ins_scroll();
1102 break;
1103
1104 case K_HOR_SCROLLBAR:
1105 ins_horscroll();
1106 break;
1107#endif
1108
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001109 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 case K_S_HOME:
1112 case K_C_HOME:
1113 ins_home(c);
1114 break;
1115
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001116 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 case K_S_END:
1119 case K_C_END:
1120 ins_end(c);
1121 break;
1122
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001123 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001124 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1125 ins_s_left();
1126 else
1127 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 break;
1129
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001130 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 case K_C_LEFT:
1132 ins_s_left();
1133 break;
1134
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001135 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001136 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1137 ins_s_right();
1138 else
1139 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001140 break;
1141
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001142 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 case K_C_RIGHT:
1144 ins_s_right();
1145 break;
1146
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001147 case K_UP: /* <Up> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001148#ifdef FEAT_INS_EXPAND
1149 if (pum_visible())
1150 goto docomplete;
1151#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001152 if (mod_mask & MOD_MASK_SHIFT)
1153 ins_pageup();
1154 else
1155 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156 break;
1157
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001158 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 case K_PAGEUP:
1160 case K_KPAGEUP:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001161#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001162 if (pum_visible())
1163 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001164#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 ins_pageup();
1166 break;
1167
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001168 case K_DOWN: /* <Down> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001169#ifdef FEAT_INS_EXPAND
1170 if (pum_visible())
1171 goto docomplete;
1172#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001173 if (mod_mask & MOD_MASK_SHIFT)
1174 ins_pagedown();
1175 else
1176 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177 break;
1178
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001179 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180 case K_PAGEDOWN:
1181 case K_KPAGEDOWN:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001182#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001183 if (pum_visible())
1184 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001185#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 ins_pagedown();
1187 break;
1188
1189#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001190 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191 ins_drop();
1192 break;
1193#endif
1194
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001195 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 c = TAB;
1197 /* FALLTHROUGH */
1198
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001199 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1201 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
1202 goto docomplete;
1203#endif
1204 inserted_space = FALSE;
1205 if (ins_tab())
1206 goto normalchar; /* insert TAB as a normal char */
1207 auto_format(FALSE, TRUE);
1208 break;
1209
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001210 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211 c = CAR;
1212 /* FALLTHROUGH */
1213 case CAR:
1214 case NL:
1215#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
1216 /* In a quickfix window a <CR> jumps to the error under the
1217 * cursor. */
1218 if (bt_quickfix(curbuf) && c == CAR)
1219 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001220 if (curwin->w_llist_ref == NULL) /* quickfix window */
1221 do_cmdline_cmd((char_u *)".cc");
1222 else /* location list window */
1223 do_cmdline_cmd((char_u *)".ll");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224 break;
1225 }
1226#endif
1227#ifdef FEAT_CMDWIN
1228 if (cmdwin_type != 0)
1229 {
1230 /* Execute the command in the cmdline window. */
1231 cmdwin_result = CAR;
1232 goto doESCkey;
1233 }
1234#endif
1235 if (ins_eol(c) && !p_im)
1236 goto doESCkey; /* out of memory */
1237 auto_format(FALSE, FALSE);
1238 inserted_space = FALSE;
1239 break;
1240
1241#if defined(FEAT_DIGRAPHS) || defined (FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001242 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243# ifdef FEAT_INS_EXPAND
1244 if (ctrl_x_mode == CTRL_X_DICTIONARY)
1245 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001246 if (has_compl_option(TRUE))
1247 goto docomplete;
1248 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 }
1250# endif
1251# ifdef FEAT_DIGRAPHS
1252 c = ins_digraph();
1253 if (c == NUL)
1254 break;
1255# endif
1256 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001257#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258
1259#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001260 case Ctrl_X: /* Enter CTRL-X mode */
1261 ins_ctrl_x();
1262 break;
1263
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001264 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 if (ctrl_x_mode != CTRL_X_TAGS)
1266 goto normalchar;
1267 goto docomplete;
1268
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001269 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001270 if (ctrl_x_mode != CTRL_X_FILES)
1271 goto normalchar;
1272 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001273
1274 case 's': /* Spelling completion after ^X */
1275 case Ctrl_S:
1276 if (ctrl_x_mode != CTRL_X_SPELL)
1277 goto normalchar;
1278 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279#endif
1280
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001281 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282#ifdef FEAT_INS_EXPAND
1283 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
1284#endif
1285 {
1286 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1287 if (p_im)
1288 {
1289 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1290 break;
1291 goto doESCkey;
1292 }
1293 goto normalchar;
1294 }
1295#ifdef FEAT_INS_EXPAND
1296 /* FALLTHROUGH */
1297
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001298 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 case Ctrl_N:
1300 /* if 'complete' is empty then plain ^P is no longer special,
1301 * but it is under other ^X modes */
1302 if (*curbuf->b_p_cpt == NUL
1303 && ctrl_x_mode != 0
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001304 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 goto normalchar;
1306
1307docomplete:
1308 if (ins_complete(c) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001309 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 break;
1311#endif /* FEAT_INS_EXPAND */
1312
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001313 case Ctrl_Y: /* copy from previous line or scroll down */
1314 case Ctrl_E: /* copy from next line or scroll up */
1315 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316 break;
1317
1318 default:
1319#ifdef UNIX
1320 if (c == intr_char) /* special interrupt char */
1321 goto do_intr;
1322#endif
1323
1324 /*
1325 * Insert a nomal character.
1326 */
1327normalchar:
1328#ifdef FEAT_SMARTINDENT
1329 /* Try to perform smart-indenting. */
1330 ins_try_si(c);
1331#endif
1332
1333 if (c == ' ')
1334 {
1335 inserted_space = TRUE;
1336#ifdef FEAT_CINDENT
1337 if (inindent(0))
1338 can_cindent = FALSE;
1339#endif
1340 if (Insstart_blank_vcol == MAXCOL
1341 && curwin->w_cursor.lnum == Insstart.lnum)
1342 Insstart_blank_vcol = get_nolist_virtcol();
1343 }
1344
1345 if (vim_iswordc(c) || !echeck_abbr(
1346#ifdef FEAT_MBYTE
1347 /* Add ABBR_OFF for characters above 0x100, this is
1348 * what check_abbr() expects. */
1349 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1350#endif
1351 c))
1352 {
1353 insert_special(c, FALSE, FALSE);
1354#ifdef FEAT_RIGHTLEFT
1355 revins_legal++;
1356 revins_chars++;
1357#endif
1358 }
1359
1360 auto_format(FALSE, TRUE);
1361
1362#ifdef FEAT_FOLDING
1363 /* When inserting a character the cursor line must never be in a
1364 * closed fold. */
1365 foldOpenCursor();
1366#endif
1367 break;
1368 } /* end of switch (c) */
1369
1370 /* If the cursor was moved we didn't just insert a space */
1371 if (arrow_used)
1372 inserted_space = FALSE;
1373
1374#ifdef FEAT_CINDENT
1375 if (can_cindent && cindent_on()
1376# ifdef FEAT_INS_EXPAND
1377 && ctrl_x_mode == 0
1378# endif
1379 )
1380 {
1381force_cindent:
1382 /*
1383 * Indent now if a key was typed that is in 'cinkeys'.
1384 */
1385 if (in_cinkeys(c, ' ', line_is_white))
1386 {
1387 if (stop_arrow() == OK)
1388 /* re-indent the current line */
1389 do_c_expr_indent();
1390 }
1391 }
1392#endif /* FEAT_CINDENT */
1393
1394 } /* for (;;) */
1395 /* NOTREACHED */
1396}
1397
1398/*
1399 * Redraw for Insert mode.
1400 * This is postponed until getting the next character to make '$' in the 'cpo'
1401 * option work correctly.
1402 * Only redraw when there are no characters available. This speeds up
1403 * inserting sequences of characters (e.g., for CTRL-R).
1404 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001405/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 static void
Bram Moolenaar754b5602006-02-09 23:53:20 +00001407ins_redraw(ready)
1408 int ready; /* not busy with something */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409{
1410 if (!char_avail())
1411 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00001412#ifdef FEAT_AUTOCMD
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001413 /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
1414 * visible, the command might delete it. */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001415 if (ready && has_cursormovedI()
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001416 && !equalpos(last_cursormoved, curwin->w_cursor)
1417# ifdef FEAT_INS_EXPAND
1418 && !pum_visible()
1419# endif
1420 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00001421 {
1422 apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, FALSE, curbuf);
1423 last_cursormoved = curwin->w_cursor;
1424 }
1425#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426 if (must_redraw)
1427 update_screen(0);
1428 else if (clear_cmdline || redraw_cmdline)
1429 showmode(); /* clear cmdline and show mode */
1430 showruler(FALSE);
1431 setcursor();
1432 emsg_on_display = FALSE; /* may remove error message now */
1433 }
1434}
1435
1436/*
1437 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1438 */
1439 static void
1440ins_ctrl_v()
1441{
1442 int c;
1443
1444 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001445 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446
1447 if (redrawing() && !char_avail())
1448 edit_putchar('^', TRUE);
1449 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1450
1451#ifdef FEAT_CMDL_INFO
1452 add_to_showcmd_c(Ctrl_V);
1453#endif
1454
1455 c = get_literal();
1456#ifdef FEAT_CMDL_INFO
1457 clear_showcmd();
1458#endif
1459 insert_special(c, FALSE, TRUE);
1460#ifdef FEAT_RIGHTLEFT
1461 revins_chars++;
1462 revins_legal++;
1463#endif
1464}
1465
1466/*
1467 * Put a character directly onto the screen. It's not stored in a buffer.
1468 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1469 */
1470static int pc_status;
1471#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1472#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1473#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1474#define PC_STATUS_SET 3 /* pc_bytes was filled */
1475#ifdef FEAT_MBYTE
1476static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1477#else
1478static char_u pc_bytes[2]; /* saved bytes */
1479#endif
1480static int pc_attr;
1481static int pc_row;
1482static int pc_col;
1483
1484 void
1485edit_putchar(c, highlight)
1486 int c;
1487 int highlight;
1488{
1489 int attr;
1490
1491 if (ScreenLines != NULL)
1492 {
1493 update_topline(); /* just in case w_topline isn't valid */
1494 validate_cursor();
1495 if (highlight)
1496 attr = hl_attr(HLF_8);
1497 else
1498 attr = 0;
1499 pc_row = W_WINROW(curwin) + curwin->w_wrow;
1500 pc_col = W_WINCOL(curwin);
1501#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1502 pc_status = PC_STATUS_UNSET;
1503#endif
1504#ifdef FEAT_RIGHTLEFT
1505 if (curwin->w_p_rl)
1506 {
1507 pc_col += W_WIDTH(curwin) - 1 - curwin->w_wcol;
1508# ifdef FEAT_MBYTE
1509 if (has_mbyte)
1510 {
1511 int fix_col = mb_fix_col(pc_col, pc_row);
1512
1513 if (fix_col != pc_col)
1514 {
1515 screen_putchar(' ', pc_row, fix_col, attr);
1516 --curwin->w_wcol;
1517 pc_status = PC_STATUS_RIGHT;
1518 }
1519 }
1520# endif
1521 }
1522 else
1523#endif
1524 {
1525 pc_col += curwin->w_wcol;
1526#ifdef FEAT_MBYTE
1527 if (mb_lefthalve(pc_row, pc_col))
1528 pc_status = PC_STATUS_LEFT;
1529#endif
1530 }
1531
1532 /* save the character to be able to put it back */
1533#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1534 if (pc_status == PC_STATUS_UNSET)
1535#endif
1536 {
1537 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1538 pc_status = PC_STATUS_SET;
1539 }
1540 screen_putchar(c, pc_row, pc_col, attr);
1541 }
1542}
1543
1544/*
1545 * Undo the previous edit_putchar().
1546 */
1547 void
1548edit_unputchar()
1549{
1550 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1551 {
1552#if defined(FEAT_MBYTE)
1553 if (pc_status == PC_STATUS_RIGHT)
1554 ++curwin->w_wcol;
1555 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
1556 redrawWinline(curwin->w_cursor.lnum, FALSE);
1557 else
1558#endif
1559 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1560 }
1561}
1562
1563/*
1564 * Called when p_dollar is set: display a '$' at the end of the changed text
1565 * Only works when cursor is in the line that changes.
1566 */
1567 void
1568display_dollar(col)
1569 colnr_T col;
1570{
1571 colnr_T save_col;
1572
1573 if (!redrawing())
1574 return;
1575
1576 cursor_off();
1577 save_col = curwin->w_cursor.col;
1578 curwin->w_cursor.col = col;
1579#ifdef FEAT_MBYTE
1580 if (has_mbyte)
1581 {
1582 char_u *p;
1583
1584 /* If on the last byte of a multi-byte move to the first byte. */
1585 p = ml_get_curline();
1586 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1587 }
1588#endif
1589 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
1590 if (curwin->w_wcol < W_WIDTH(curwin))
1591 {
1592 edit_putchar('$', FALSE);
1593 dollar_vcol = curwin->w_virtcol;
1594 }
1595 curwin->w_cursor.col = save_col;
1596}
1597
1598/*
1599 * Call this function before moving the cursor from the normal insert position
1600 * in insert mode.
1601 */
1602 static void
1603undisplay_dollar()
1604{
1605 if (dollar_vcol)
1606 {
1607 dollar_vcol = 0;
1608 redrawWinline(curwin->w_cursor.lnum, FALSE);
1609 }
1610}
1611
1612/*
1613 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1614 * Keep the cursor on the same character.
1615 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1616 * type == INDENT_DEC decrease indent (for CTRL-D)
1617 * type == INDENT_SET set indent to "amount"
1618 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1619 */
1620 void
1621change_indent(type, amount, round, replaced)
1622 int type;
1623 int amount;
1624 int round;
1625 int replaced; /* replaced character, put on replace stack */
1626{
1627 int vcol;
1628 int last_vcol;
1629 int insstart_less; /* reduction for Insstart.col */
1630 int new_cursor_col;
1631 int i;
1632 char_u *ptr;
1633 int save_p_list;
1634 int start_col;
1635 colnr_T vc;
1636#ifdef FEAT_VREPLACE
1637 colnr_T orig_col = 0; /* init for GCC */
1638 char_u *new_line, *orig_line = NULL; /* init for GCC */
1639
1640 /* VREPLACE mode needs to know what the line was like before changing */
1641 if (State & VREPLACE_FLAG)
1642 {
1643 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1644 orig_col = curwin->w_cursor.col;
1645 }
1646#endif
1647
1648 /* for the following tricks we don't want list mode */
1649 save_p_list = curwin->w_p_list;
1650 curwin->w_p_list = FALSE;
1651 vc = getvcol_nolist(&curwin->w_cursor);
1652 vcol = vc;
1653
1654 /*
1655 * For Replace mode we need to fix the replace stack later, which is only
1656 * possible when the cursor is in the indent. Remember the number of
1657 * characters before the cursor if it's possible.
1658 */
1659 start_col = curwin->w_cursor.col;
1660
1661 /* determine offset from first non-blank */
1662 new_cursor_col = curwin->w_cursor.col;
1663 beginline(BL_WHITE);
1664 new_cursor_col -= curwin->w_cursor.col;
1665
1666 insstart_less = curwin->w_cursor.col;
1667
1668 /*
1669 * If the cursor is in the indent, compute how many screen columns the
1670 * cursor is to the left of the first non-blank.
1671 */
1672 if (new_cursor_col < 0)
1673 vcol = get_indent() - vcol;
1674
1675 if (new_cursor_col > 0) /* can't fix replace stack */
1676 start_col = -1;
1677
1678 /*
1679 * Set the new indent. The cursor will be put on the first non-blank.
1680 */
1681 if (type == INDENT_SET)
1682 (void)set_indent(amount, SIN_CHANGED);
1683 else
1684 {
1685#ifdef FEAT_VREPLACE
1686 int save_State = State;
1687
1688 /* Avoid being called recursively. */
1689 if (State & VREPLACE_FLAG)
1690 State = INSERT;
1691#endif
1692 shift_line(type == INDENT_DEC, round, 1);
1693#ifdef FEAT_VREPLACE
1694 State = save_State;
1695#endif
1696 }
1697 insstart_less -= curwin->w_cursor.col;
1698
1699 /*
1700 * Try to put cursor on same character.
1701 * If the cursor is at or after the first non-blank in the line,
1702 * compute the cursor column relative to the column of the first
1703 * non-blank character.
1704 * If we are not in insert mode, leave the cursor on the first non-blank.
1705 * If the cursor is before the first non-blank, position it relative
1706 * to the first non-blank, counted in screen columns.
1707 */
1708 if (new_cursor_col >= 0)
1709 {
1710 /*
1711 * When changing the indent while the cursor is touching it, reset
1712 * Insstart_col to 0.
1713 */
1714 if (new_cursor_col == 0)
1715 insstart_less = MAXCOL;
1716 new_cursor_col += curwin->w_cursor.col;
1717 }
1718 else if (!(State & INSERT))
1719 new_cursor_col = curwin->w_cursor.col;
1720 else
1721 {
1722 /*
1723 * Compute the screen column where the cursor should be.
1724 */
1725 vcol = get_indent() - vcol;
1726 curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
1727
1728 /*
1729 * Advance the cursor until we reach the right screen column.
1730 */
1731 vcol = last_vcol = 0;
1732 new_cursor_col = -1;
1733 ptr = ml_get_curline();
1734 while (vcol <= (int)curwin->w_virtcol)
1735 {
1736 last_vcol = vcol;
1737#ifdef FEAT_MBYTE
1738 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001739 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 else
1741#endif
1742 ++new_cursor_col;
1743 vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
1744 }
1745 vcol = last_vcol;
1746
1747 /*
1748 * May need to insert spaces to be able to position the cursor on
1749 * the right screen column.
1750 */
1751 if (vcol != (int)curwin->w_virtcol)
1752 {
1753 curwin->w_cursor.col = new_cursor_col;
1754 i = (int)curwin->w_virtcol - vcol;
1755 ptr = alloc(i + 1);
1756 if (ptr != NULL)
1757 {
1758 new_cursor_col += i;
1759 ptr[i] = NUL;
1760 while (--i >= 0)
1761 ptr[i] = ' ';
1762 ins_str(ptr);
1763 vim_free(ptr);
1764 }
1765 }
1766
1767 /*
1768 * When changing the indent while the cursor is in it, reset
1769 * Insstart_col to 0.
1770 */
1771 insstart_less = MAXCOL;
1772 }
1773
1774 curwin->w_p_list = save_p_list;
1775
1776 if (new_cursor_col <= 0)
1777 curwin->w_cursor.col = 0;
1778 else
1779 curwin->w_cursor.col = new_cursor_col;
1780 curwin->w_set_curswant = TRUE;
1781 changed_cline_bef_curs();
1782
1783 /*
1784 * May have to adjust the start of the insert.
1785 */
1786 if (State & INSERT)
1787 {
1788 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1789 {
1790 if ((int)Insstart.col <= insstart_less)
1791 Insstart.col = 0;
1792 else
1793 Insstart.col -= insstart_less;
1794 }
1795 if ((int)ai_col <= insstart_less)
1796 ai_col = 0;
1797 else
1798 ai_col -= insstart_less;
1799 }
1800
1801 /*
1802 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1803 * If the number of characters before the cursor decreased, need to pop a
1804 * few characters from the replace stack.
1805 * If the number of characters before the cursor increased, need to push a
1806 * few NULs onto the replace stack.
1807 */
1808 if (REPLACE_NORMAL(State) && start_col >= 0)
1809 {
1810 while (start_col > (int)curwin->w_cursor.col)
1811 {
1812 replace_join(0); /* remove a NUL from the replace stack */
1813 --start_col;
1814 }
1815 while (start_col < (int)curwin->w_cursor.col || replaced)
1816 {
1817 replace_push(NUL);
1818 if (replaced)
1819 {
1820 replace_push(replaced);
1821 replaced = NUL;
1822 }
1823 ++start_col;
1824 }
1825 }
1826
1827#ifdef FEAT_VREPLACE
1828 /*
1829 * For VREPLACE mode, we also have to fix the replace stack. In this case
1830 * it is always possible because we backspace over the whole line and then
1831 * put it back again the way we wanted it.
1832 */
1833 if (State & VREPLACE_FLAG)
1834 {
1835 /* If orig_line didn't allocate, just return. At least we did the job,
1836 * even if you can't backspace. */
1837 if (orig_line == NULL)
1838 return;
1839
1840 /* Save new line */
1841 new_line = vim_strsave(ml_get_curline());
1842 if (new_line == NULL)
1843 return;
1844
1845 /* We only put back the new line up to the cursor */
1846 new_line[curwin->w_cursor.col] = NUL;
1847
1848 /* Put back original line */
1849 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1850 curwin->w_cursor.col = orig_col;
1851
1852 /* Backspace from cursor to start of line */
1853 backspace_until_column(0);
1854
1855 /* Insert new stuff into line again */
1856 ins_bytes(new_line);
1857
1858 vim_free(new_line);
1859 }
1860#endif
1861}
1862
1863/*
1864 * Truncate the space at the end of a line. This is to be used only in an
1865 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1866 * modes.
1867 */
1868 void
1869truncate_spaces(line)
1870 char_u *line;
1871{
1872 int i;
1873
1874 /* find start of trailing white space */
1875 for (i = (int)STRLEN(line) - 1; i >= 0 && vim_iswhite(line[i]); i--)
1876 {
1877 if (State & REPLACE_FLAG)
1878 replace_join(0); /* remove a NUL from the replace stack */
1879 }
1880 line[i + 1] = NUL;
1881}
1882
1883#if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \
1884 || defined(FEAT_COMMENTS) || defined(PROTO)
1885/*
1886 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1887 * modes correctly. May also be used when not in insert mode at all.
1888 */
1889 void
1890backspace_until_column(col)
1891 int col;
1892{
1893 while ((int)curwin->w_cursor.col > col)
1894 {
1895 curwin->w_cursor.col--;
1896 if (State & REPLACE_FLAG)
1897 replace_do_bs();
1898 else
1899 (void)del_char(FALSE);
1900 }
1901}
1902#endif
1903
1904#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1905/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001906 * CTRL-X pressed in Insert mode.
1907 */
1908 static void
1909ins_ctrl_x()
1910{
1911 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1912 * CTRL-V works like CTRL-N */
1913 if (ctrl_x_mode != CTRL_X_CMDLINE)
1914 {
1915 /* if the next ^X<> won't ADD nothing, then reset
1916 * compl_cont_status */
1917 if (compl_cont_status & CONT_N_ADDS)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001918 compl_cont_status |= CONT_INTRPT;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001919 else
1920 compl_cont_status = 0;
1921 /* We're not sure which CTRL-X mode it will be yet */
1922 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1923 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1924 edit_submode_pre = NULL;
1925 showmode();
1926 }
1927}
1928
1929/*
1930 * Return TRUE if the 'dict' or 'tsr' option can be used.
1931 */
1932 static int
1933has_compl_option(dict_opt)
1934 int dict_opt;
1935{
Bram Moolenaar0b238792006-03-02 22:49:12 +00001936 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00001937# ifdef FEAT_SPELL
1938 && !curwin->w_p_spell
1939# endif
1940 )
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001941 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
1942 {
1943 ctrl_x_mode = 0;
1944 edit_submode = NULL;
1945 msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
1946 : (char_u *)_("'thesaurus' option is empty"),
1947 hl_attr(HLF_E));
1948 if (emsg_silent == 0)
1949 {
1950 vim_beep();
1951 setcursor();
1952 out_flush();
1953 ui_delay(2000L, FALSE);
1954 }
1955 return FALSE;
1956 }
1957 return TRUE;
1958}
1959
1960/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961 * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
1962 * This depends on the current mode.
1963 */
1964 int
1965vim_is_ctrl_x_key(c)
1966 int c;
1967{
1968 /* Always allow ^R - let it's results then be checked */
1969 if (c == Ctrl_R)
1970 return TRUE;
1971
Bram Moolenaare3226be2005-12-18 22:10:00 +00001972 /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001973 if (ins_compl_pum_key(c))
Bram Moolenaare3226be2005-12-18 22:10:00 +00001974 return TRUE;
1975
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 switch (ctrl_x_mode)
1977 {
1978 case 0: /* Not in any CTRL-X mode */
1979 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
1980 case CTRL_X_NOT_DEFINED_YET:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001981 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1983 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
1984 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
Bram Moolenaar488c6512005-08-11 20:09:58 +00001985 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
1986 || c == Ctrl_S || c == 's');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 case CTRL_X_SCROLL:
1988 return (c == Ctrl_Y || c == Ctrl_E);
1989 case CTRL_X_WHOLE_LINE:
1990 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
1991 case CTRL_X_FILES:
1992 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
1993 case CTRL_X_DICTIONARY:
1994 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
1995 case CTRL_X_THESAURUS:
1996 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
1997 case CTRL_X_TAGS:
1998 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
1999#ifdef FEAT_FIND_ID
2000 case CTRL_X_PATH_PATTERNS:
2001 return (c == Ctrl_P || c == Ctrl_N);
2002 case CTRL_X_PATH_DEFINES:
2003 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
2004#endif
2005 case CTRL_X_CMDLINE:
2006 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
2007 || c == Ctrl_X);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002008#ifdef FEAT_COMPL_FUNC
2009 case CTRL_X_FUNCTION:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002010 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002011 case CTRL_X_OMNI:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002012 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002013#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002014 case CTRL_X_SPELL:
2015 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016 }
2017 EMSG(_(e_internal));
2018 return FALSE;
2019}
2020
2021/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002022 * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 * case of the originally typed text is used, and the case of the completed
2024 * text is infered, ie this tries to work out what case you probably wanted
2025 * the rest of the word to be in -- webb
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002026 * TODO: make this work for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 */
2028 int
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002029ins_compl_add_infercase(str, len, icase, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030 char_u *str;
2031 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002032 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033 char_u *fname;
2034 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002035 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036{
2037 int has_lower = FALSE;
2038 int was_letter = FALSE;
2039 int idx;
2040
2041 if (p_ic && curbuf->b_p_inf && len < IOSIZE)
2042 {
2043 /* Infer case of completed part -- webb */
2044 /* Use IObuff, str would change text in buffer! */
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002045 vim_strncpy(IObuff, str, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046
2047 /* Rule 1: Were any chars converted to lower? */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002048 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002050 if (islower(compl_orig_text[idx]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 {
2052 has_lower = TRUE;
2053 if (isupper(IObuff[idx]))
2054 {
2055 /* Rule 1 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002056 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
2058 break;
2059 }
2060 }
2061 }
2062
2063 /*
2064 * Rule 2: No lower case, 2nd consecutive letter converted to
2065 * upper case.
2066 */
2067 if (!has_lower)
2068 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002069 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002071 if (was_letter && isupper(compl_orig_text[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072 && islower(IObuff[idx]))
2073 {
2074 /* Rule 2 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002075 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076 IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
2077 break;
2078 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002079 was_letter = isalpha(compl_orig_text[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 }
2081 }
2082
2083 /* Copy the original case of the part we typed */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002084 STRNCPY(IObuff, compl_orig_text, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002086 return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
2087 flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 }
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002089 return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090}
2091
2092/*
2093 * Add a match to the list of matches.
2094 * If the given string is already in the list of completions, then return
Bram Moolenaar572cb562005-08-05 21:35:02 +00002095 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002096 * maybe because alloc() returns NULL, then FAIL is returned.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002098 static int
2099ins_compl_add(str, len, icase, fname, cptext, cdir, flags, dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 char_u *str;
2101 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002102 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 char_u *fname;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002104 char_u **cptext; /* extra text for popup menu or NULL */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002105 int cdir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002106 int flags;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002107 int dup; /* accept duplicate match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002109 compl_T *match;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002110 int dir = (cdir == 0 ? compl_direction : cdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111
2112 ui_breakcheck();
2113 if (got_int)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002114 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 if (len < 0)
2116 len = (int)STRLEN(str);
2117
2118 /*
2119 * If the same match is already present, don't add it.
2120 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002121 if (compl_first_match != NULL && !dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002123 match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 do
2125 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002126 if ( !(match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002127 && ins_compl_equal(match, str, len)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002128 && match->cp_str[len] == NUL)
2129 return NOTDONE;
2130 match = match->cp_next;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002131 } while (match != NULL && match != compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 }
2133
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002134 /* Remove any popup menu before changing the list of matches. */
2135 ins_compl_del_pum();
2136
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 /*
2138 * Allocate a new match structure.
2139 * Copy the values to the new match structure.
2140 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002141 match = (compl_T *)alloc_clear((unsigned)sizeof(compl_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142 if (match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002143 return FAIL;
2144 match->cp_number = -1;
2145 if (flags & ORIGINAL_TEXT)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002146 match->cp_number = 0;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002147 if ((match->cp_str = vim_strnsave(str, len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 {
2149 vim_free(match);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002150 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002152 match->cp_icase = icase;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002153
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154 /* match-fname is:
Bram Moolenaar572cb562005-08-05 21:35:02 +00002155 * - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
2157 * - NULL otherwise. --Acevedo */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002158 if (fname != NULL
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002159 && compl_curr_match != NULL
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002160 && compl_curr_match->cp_fname != NULL
2161 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002162 match->cp_fname = compl_curr_match->cp_fname;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002163 else if (fname != NULL)
2164 {
2165 match->cp_fname = vim_strsave(fname);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002166 flags |= FREE_FNAME;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 else
Bram Moolenaar572cb562005-08-05 21:35:02 +00002169 match->cp_fname = NULL;
2170 match->cp_flags = flags;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002171
2172 if (cptext != NULL)
2173 {
2174 int i;
2175
2176 for (i = 0; i < CPT_COUNT; ++i)
2177 if (cptext[i] != NULL && *cptext[i] != NUL)
2178 match->cp_text[i] = vim_strsave(cptext[i]);
2179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180
2181 /*
2182 * Link the new match structure in the list of matches.
2183 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002184 if (compl_first_match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002185 match->cp_next = match->cp_prev = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002186 else if (dir == FORWARD)
2187 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002188 match->cp_next = compl_curr_match->cp_next;
2189 match->cp_prev = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190 }
2191 else /* BACKWARD */
2192 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002193 match->cp_next = compl_curr_match;
2194 match->cp_prev = compl_curr_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002196 if (match->cp_next)
2197 match->cp_next->cp_prev = match;
2198 if (match->cp_prev)
2199 match->cp_prev->cp_next = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 else /* if there's nothing before, it is the first match */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002201 compl_first_match = match;
2202 compl_curr_match = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002204 /*
2205 * Find the longest common string if still doing that.
2206 */
2207 if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
2208 ins_compl_longest_match(match);
2209
Bram Moolenaar071d4272004-06-13 20:20:40 +00002210 return OK;
2211}
2212
2213/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002214 * Return TRUE if "str[len]" matches with match->cp_str, considering
2215 * match->cp_icase.
2216 */
2217 static int
2218ins_compl_equal(match, str, len)
2219 compl_T *match;
2220 char_u *str;
2221 int len;
2222{
2223 if (match->cp_icase)
2224 return STRNICMP(match->cp_str, str, (size_t)len) == 0;
2225 return STRNCMP(match->cp_str, str, (size_t)len) == 0;
2226}
2227
2228/*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002229 * Reduce the longest common string for match "match".
2230 */
2231 static void
2232ins_compl_longest_match(match)
2233 compl_T *match;
2234{
2235 char_u *p, *s;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002236 int c1, c2;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002237 int had_match;
2238
2239 if (compl_leader == NULL)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002240 {
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002241 /* First match, use it as a whole. */
2242 compl_leader = vim_strsave(match->cp_str);
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002243 if (compl_leader != NULL)
2244 {
2245 had_match = (curwin->w_cursor.col > compl_col);
2246 ins_compl_delete();
2247 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2248 ins_redraw(FALSE);
2249
2250 /* When the match isn't there (to avoid matching itself) remove it
2251 * again after redrawing. */
2252 if (!had_match)
2253 ins_compl_delete();
2254 compl_used_match = FALSE;
2255 }
2256 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002257 else
2258 {
2259 /* Reduce the text if this match differs from compl_leader. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002260 p = compl_leader;
2261 s = match->cp_str;
2262 while (*p != NUL)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002263 {
2264#ifdef FEAT_MBYTE
2265 if (has_mbyte)
2266 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002267 c1 = mb_ptr2char(p);
2268 c2 = mb_ptr2char(s);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002269 }
2270 else
2271#endif
2272 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002273 c1 = *p;
2274 c2 = *s;
2275 }
2276 if (match->cp_icase ? (MB_TOLOWER(c1) != MB_TOLOWER(c2))
2277 : (c1 != c2))
2278 break;
2279#ifdef FEAT_MBYTE
2280 if (has_mbyte)
2281 {
2282 mb_ptr_adv(p);
2283 mb_ptr_adv(s);
2284 }
2285 else
2286#endif
2287 {
2288 ++p;
2289 ++s;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002290 }
2291 }
2292
2293 if (*p != NUL)
2294 {
2295 /* Leader was shortened, need to change the inserted text. */
2296 *p = NUL;
2297 had_match = (curwin->w_cursor.col > compl_col);
2298 ins_compl_delete();
2299 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2300 ins_redraw(FALSE);
2301
2302 /* When the match isn't there (to avoid matching itself) remove it
2303 * again after redrawing. */
2304 if (!had_match)
2305 ins_compl_delete();
2306 }
2307
2308 compl_used_match = FALSE;
2309 }
2310}
2311
2312/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 * Add an array of matches to the list of matches.
2314 * Frees matches[].
2315 */
2316 static void
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002317ins_compl_add_matches(num_matches, matches, icase)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318 int num_matches;
2319 char_u **matches;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002320 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321{
2322 int i;
2323 int add_r = OK;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002324 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325
Bram Moolenaar572cb562005-08-05 21:35:02 +00002326 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002327 if ((add_r = ins_compl_add(matches[i], -1, icase,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002328 NULL, NULL, dir, 0, FALSE)) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 /* if dir was BACKWARD then honor it just once */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002330 dir = FORWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 FreeWild(num_matches, matches);
2332}
2333
2334/* Make the completion list cyclic.
2335 * Return the number of matches (excluding the original).
2336 */
2337 static int
2338ins_compl_make_cyclic()
2339{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002340 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 int count = 0;
2342
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002343 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344 {
2345 /*
2346 * Find the end of the list.
2347 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002348 match = compl_first_match;
2349 /* there's always an entry for the compl_orig_text, it doesn't count. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002350 while (match->cp_next != NULL && match->cp_next != compl_first_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002352 match = match->cp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 ++count;
2354 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002355 match->cp_next = compl_first_match;
2356 compl_first_match->cp_prev = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 }
2358 return count;
2359}
2360
Bram Moolenaara94bc432006-03-10 21:42:59 +00002361/*
2362 * Start completion for the complete() function.
2363 * "startcol" is where the matched text starts (1 is first column).
2364 * "list" is the list of matches.
2365 */
2366 void
2367set_completion(startcol, list)
2368 int startcol;
2369 list_T *list;
2370{
2371 /* If already doing completions stop it. */
2372 if (ctrl_x_mode != 0)
2373 ins_compl_prep(' ');
2374 ins_compl_clear();
2375
2376 if (stop_arrow() == FAIL)
2377 return;
2378
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002379 if (startcol > (int)curwin->w_cursor.col)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002380 startcol = curwin->w_cursor.col;
2381 compl_col = startcol;
2382 compl_length = curwin->w_cursor.col - startcol;
2383 /* compl_pattern doesn't need to be set */
2384 compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
2385 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002386 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002387 return;
2388
2389 /* Handle like dictionary completion. */
2390 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2391
2392 ins_compl_add_list(list);
2393 compl_matches = ins_compl_make_cyclic();
2394 compl_started = TRUE;
2395 compl_used_match = TRUE;
2396
2397 compl_curr_match = compl_first_match;
2398 ins_complete(Ctrl_N);
2399 out_flush();
2400}
2401
2402
Bram Moolenaar9372a112005-12-06 19:59:18 +00002403/* "compl_match_array" points the currently displayed list of entries in the
2404 * popup menu. It is NULL when there is no popup menu. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002405static pumitem_T *compl_match_array = NULL;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002406static int compl_match_arraysize;
2407
2408/*
2409 * Update the screen and when there is any scrolling remove the popup menu.
2410 */
2411 static void
2412ins_compl_upd_pum()
2413{
2414 int h;
2415
2416 if (compl_match_array != NULL)
2417 {
2418 h = curwin->w_cline_height;
2419 update_screen(0);
2420 if (h != curwin->w_cline_height)
2421 ins_compl_del_pum();
2422 }
2423}
2424
2425/*
2426 * Remove any popup menu.
2427 */
2428 static void
2429ins_compl_del_pum()
2430{
2431 if (compl_match_array != NULL)
2432 {
2433 pum_undisplay();
2434 vim_free(compl_match_array);
2435 compl_match_array = NULL;
2436 }
2437}
2438
2439/*
2440 * Return TRUE if the popup menu should be displayed.
2441 */
2442 static int
2443pum_wanted()
2444{
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002445 /* 'completeopt' must contain "menu" or "menuone" */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002446 if (vim_strchr(p_cot, 'm') == NULL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002447 return FALSE;
2448
2449 /* The display looks bad on a B&W display. */
2450 if (t_colors < 8
2451#ifdef FEAT_GUI
2452 && !gui.in_use
2453#endif
2454 )
2455 return FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +00002456 return TRUE;
2457}
2458
2459/*
2460 * Return TRUE if there are two or more matches to be shown in the popup menu.
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002461 * One if 'completopt' contains "menuone".
Bram Moolenaara6557602006-02-04 22:43:20 +00002462 */
2463 static int
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002464pum_enough_matches()
Bram Moolenaara6557602006-02-04 22:43:20 +00002465{
2466 compl_T *compl;
2467 int i;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002468
2469 /* Don't display the popup menu if there are no matches or there is only
2470 * one (ignoring the original text). */
2471 compl = compl_first_match;
2472 i = 0;
2473 do
2474 {
2475 if (compl == NULL
2476 || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
2477 break;
2478 compl = compl->cp_next;
2479 } while (compl != compl_first_match);
2480
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002481 if (strstr((char *)p_cot, "menuone") != NULL)
2482 return (i >= 1);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002483 return (i >= 2);
2484}
2485
2486/*
2487 * Show the popup menu for the list of matches.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002488 * Also adjusts "compl_shown_match" to an entry that is actually displayed.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002489 */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002490 void
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002491ins_compl_show_pum()
2492{
2493 compl_T *compl;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002494 compl_T *shown_compl = NULL;
2495 int did_find_shown_match = FALSE;
2496 int shown_match_ok = FALSE;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002497 int i;
2498 int cur = -1;
2499 colnr_T col;
Bram Moolenaara6557602006-02-04 22:43:20 +00002500 int lead_len = 0;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002501
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002502 if (!pum_wanted() || !pum_enough_matches())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002503 return;
2504
Bram Moolenaar433f7c82006-03-21 21:29:36 +00002505#if defined(FEAT_EVAL)
2506 /* Dirty hard-coded hack: remove any matchparen highlighting. */
2507 do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|3match none|endif");
2508#endif
2509
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002510 /* Update the screen before drawing the popup menu over it. */
2511 update_screen(0);
2512
2513 if (compl_match_array == NULL)
2514 {
2515 /* Need to build the popup menu list. */
2516 compl_match_arraysize = 0;
2517 compl = compl_first_match;
Bram Moolenaara6557602006-02-04 22:43:20 +00002518 if (compl_leader != NULL)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002519 lead_len = (int)STRLEN(compl_leader);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002520 do
2521 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002522 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2523 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002524 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002525 ++compl_match_arraysize;
2526 compl = compl->cp_next;
2527 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaara6557602006-02-04 22:43:20 +00002528 if (compl_match_arraysize == 0)
2529 return;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002530 compl_match_array = (pumitem_T *)alloc_clear(
2531 (unsigned)(sizeof(pumitem_T)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002532 * compl_match_arraysize));
2533 if (compl_match_array != NULL)
2534 {
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002535 /* If the current match is the original text don't find the first
2536 * match after it, don't highlight anything. */
2537 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
2538 shown_match_ok = TRUE;
2539
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002540 i = 0;
2541 compl = compl_first_match;
2542 do
2543 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002544 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2545 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002546 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002547 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002548 if (!shown_match_ok)
2549 {
2550 if (compl == compl_shown_match || did_find_shown_match)
2551 {
2552 /* This item is the shown match or this is the
2553 * first displayed item after the shown match. */
2554 compl_shown_match = compl;
2555 did_find_shown_match = TRUE;
2556 shown_match_ok = TRUE;
2557 }
2558 else
2559 /* Remember this displayed match for when the
2560 * shown match is just below it. */
2561 shown_compl = compl;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002562 cur = i;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002563 }
Bram Moolenaar39f05632006-03-19 22:15:26 +00002564
2565 if (compl->cp_text[CPT_ABBR] != NULL)
2566 compl_match_array[i].pum_text =
2567 compl->cp_text[CPT_ABBR];
2568 else
2569 compl_match_array[i].pum_text = compl->cp_str;
2570 compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
2571 compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
2572 if (compl->cp_text[CPT_MENU] != NULL)
2573 compl_match_array[i++].pum_extra =
2574 compl->cp_text[CPT_MENU];
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002575 else
2576 compl_match_array[i++].pum_extra = compl->cp_fname;
2577 }
2578
2579 if (compl == compl_shown_match)
2580 {
2581 did_find_shown_match = TRUE;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002582
2583 /* When the original text is the shown match don't set
2584 * compl_shown_match. */
2585 if (compl->cp_flags & ORIGINAL_TEXT)
2586 shown_match_ok = TRUE;
2587
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002588 if (!shown_match_ok && shown_compl != NULL)
2589 {
2590 /* The shown match isn't displayed, set it to the
2591 * previously displayed match. */
2592 compl_shown_match = shown_compl;
2593 shown_match_ok = TRUE;
2594 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002595 }
2596 compl = compl->cp_next;
2597 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002598
2599 if (!shown_match_ok) /* no displayed match at all */
2600 cur = -1;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002601 }
2602 }
2603 else
2604 {
2605 /* popup menu already exists, only need to find the current item.*/
Bram Moolenaara6557602006-02-04 22:43:20 +00002606 for (i = 0; i < compl_match_arraysize; ++i)
Bram Moolenaar39f05632006-03-19 22:15:26 +00002607 if (compl_match_array[i].pum_text == compl_shown_match->cp_str
2608 || compl_match_array[i].pum_text
2609 == compl_shown_match->cp_text[CPT_ABBR])
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002610 {
2611 cur = i;
Bram Moolenaara6557602006-02-04 22:43:20 +00002612 break;
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002613 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002614 }
2615
2616 if (compl_match_array != NULL)
2617 {
2618 /* Compute the screen column of the start of the completed text.
2619 * Use the cursor to get all wrapping and other settings right. */
2620 col = curwin->w_cursor.col;
2621 curwin->w_cursor.col = compl_col;
Bram Moolenaard289f132006-03-11 21:30:53 +00002622 pum_display(compl_match_array, compl_match_arraysize, cur);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002623 curwin->w_cursor.col = col;
2624 }
2625}
2626
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627#define DICT_FIRST (1) /* use just first element in "dict" */
2628#define DICT_EXACT (2) /* "dict" is the exact name of a file */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002629
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630/*
Bram Moolenaar0b238792006-03-02 22:49:12 +00002631 * Add any identifiers that match the given pattern in the list of dictionary
2632 * files "dict_start" to the list of completions.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 */
2634 static void
Bram Moolenaar0b238792006-03-02 22:49:12 +00002635ins_compl_dictionaries(dict_start, pat, flags, thesaurus)
2636 char_u *dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 char_u *pat;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002638 int flags; /* DICT_FIRST and/or DICT_EXACT */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002639 int thesaurus; /* Thesaurus completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640{
Bram Moolenaar0b238792006-03-02 22:49:12 +00002641 char_u *dict = dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 char_u *ptr;
2643 char_u *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 regmatch_T regmatch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 char_u **files;
2646 int count;
2647 int i;
2648 int save_p_scs;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002649 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650
Bram Moolenaar0b238792006-03-02 22:49:12 +00002651 if (*dict == NUL)
2652 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002653#ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002654 /* When 'dictionary' is empty and spell checking is enabled use
2655 * "spell". */
2656 if (!thesaurus && curwin->w_p_spell)
2657 dict = (char_u *)"spell";
2658 else
2659#endif
2660 return;
2661 }
2662
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 buf = alloc(LSIZE);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002664 if (buf == NULL)
2665 return;
2666
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 /* If 'infercase' is set, don't use 'smartcase' here */
2668 save_p_scs = p_scs;
2669 if (curbuf->b_p_inf)
2670 p_scs = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002671
2672 /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
2673 * to only match at the start of a line. Otherwise just match the
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002674 * pattern. Also need to double backslashes. */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002675 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2676 {
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002677 char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
2678
2679 if (pat_esc == NULL)
2680 return ;
2681 i = (int)STRLEN(pat_esc) + 10;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002682 ptr = alloc(i);
2683 if (ptr == NULL)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002684 {
2685 vim_free(pat_esc);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002686 return;
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002687 }
2688 vim_snprintf((char *)ptr, i, "^\\s*\\zs\\V%s", pat_esc);
2689 regmatch.regprog = vim_regcomp(ptr, RE_MAGIC);
2690 vim_free(pat_esc);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002691 vim_free(ptr);
2692 }
2693 else
Bram Moolenaar0b238792006-03-02 22:49:12 +00002694 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002695 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002696 if (regmatch.regprog == NULL)
2697 goto theend;
2698 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002699
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2701 regmatch.rm_ic = ignorecase(pat);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002702 while (*dict != NUL && !got_int && !compl_interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 {
2704 /* copy one dictionary file name into buf */
2705 if (flags == DICT_EXACT)
2706 {
2707 count = 1;
2708 files = &dict;
2709 }
2710 else
2711 {
2712 /* Expand wildcards in the dictionary name, but do not allow
2713 * backticks (for security, the 'dict' option may have been set in
2714 * a modeline). */
2715 copy_option_part(&dict, buf, LSIZE, ",");
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002716# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002717 if (!thesaurus && STRCMP(buf, "spell") == 0)
2718 count = -1;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002719 else
2720# endif
2721 if (vim_strchr(buf, '`') != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 || expand_wildcards(1, &buf, &count, &files,
2723 EW_FILE|EW_SILENT) != OK)
2724 count = 0;
2725 }
2726
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002727# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002728 if (count == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 {
Bram Moolenaar87b5ca52006-03-04 21:55:31 +00002730 /* Complete from active spelling. Skip "\<" in the pattern, we
2731 * don't use it as a RE. */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002732 if (pat[0] == '\\' && pat[1] == '<')
2733 ptr = pat + 2;
2734 else
2735 ptr = pat;
2736 spell_dump_compl(curbuf, ptr, regmatch.rm_ic, &dir, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002738 else
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002739# endif
Bram Moolenaar0b238792006-03-02 22:49:12 +00002740 {
2741 ins_compl_files(count, files, thesaurus, flags,
2742 &regmatch, buf, &dir);
2743 if (flags != DICT_EXACT)
2744 FreeWild(count, files);
2745 }
2746 if (flags != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747 break;
2748 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002749
2750theend:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 p_scs = save_p_scs;
2752 vim_free(regmatch.regprog);
2753 vim_free(buf);
2754}
2755
Bram Moolenaar0b238792006-03-02 22:49:12 +00002756 static void
2757ins_compl_files(count, files, thesaurus, flags, regmatch, buf, dir)
2758 int count;
2759 char_u **files;
2760 int thesaurus;
2761 int flags;
2762 regmatch_T *regmatch;
2763 char_u *buf;
2764 int *dir;
2765{
2766 char_u *ptr;
2767 int i;
2768 FILE *fp;
2769 int add_r;
2770
2771 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
2772 {
2773 fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
2774 if (flags != DICT_EXACT)
2775 {
2776 vim_snprintf((char *)IObuff, IOSIZE,
2777 _("Scanning dictionary: %s"), (char *)files[i]);
2778 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2779 }
2780
2781 if (fp != NULL)
2782 {
2783 /*
2784 * Read dictionary file line by line.
2785 * Check each line for a match.
2786 */
2787 while (!got_int && !compl_interrupted
2788 && !vim_fgets(buf, LSIZE, fp))
2789 {
2790 ptr = buf;
2791 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
2792 {
2793 ptr = regmatch->startp[0];
2794 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2795 ptr = find_line_end(ptr);
2796 else
2797 ptr = find_word_end(ptr);
2798 add_r = ins_compl_add_infercase(regmatch->startp[0],
2799 (int)(ptr - regmatch->startp[0]),
Bram Moolenaard289f132006-03-11 21:30:53 +00002800 p_ic, files[i], *dir, 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002801 if (thesaurus)
2802 {
2803 char_u *wstart;
2804
2805 /*
2806 * Add the other matches on the line
2807 */
2808 while (!got_int)
2809 {
2810 /* Find start of the next word. Skip white
2811 * space and punctuation. */
2812 ptr = find_word_start(ptr);
2813 if (*ptr == NUL || *ptr == NL)
2814 break;
2815 wstart = ptr;
2816
2817 /* Find end of the word and add it. */
2818#ifdef FEAT_MBYTE
2819 if (has_mbyte)
2820 /* Japanese words may have characters in
2821 * different classes, only separate words
2822 * with single-byte non-word characters. */
2823 while (*ptr != NUL)
2824 {
2825 int l = (*mb_ptr2len)(ptr);
2826
2827 if (l < 2 && !vim_iswordc(*ptr))
2828 break;
2829 ptr += l;
2830 }
2831 else
2832#endif
2833 ptr = find_word_end(ptr);
2834 add_r = ins_compl_add_infercase(wstart,
2835 (int)(ptr - wstart),
2836 p_ic, files[i], *dir, 0);
2837 }
2838 }
2839 if (add_r == OK)
2840 /* if dir was BACKWARD then honor it just once */
2841 *dir = FORWARD;
2842 else if (add_r == FAIL)
2843 break;
2844 /* avoid expensive call to vim_regexec() when at end
2845 * of line */
2846 if (*ptr == '\n' || got_int)
2847 break;
2848 }
2849 line_breakcheck();
2850 ins_compl_check_keys(50);
2851 }
2852 fclose(fp);
2853 }
2854 }
2855}
2856
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857/*
2858 * Find the start of the next word.
2859 * Returns a pointer to the first char of the word. Also stops at a NUL.
2860 */
2861 char_u *
2862find_word_start(ptr)
2863 char_u *ptr;
2864{
2865#ifdef FEAT_MBYTE
2866 if (has_mbyte)
2867 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002868 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869 else
2870#endif
2871 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2872 ++ptr;
2873 return ptr;
2874}
2875
2876/*
2877 * Find the end of the word. Assumes it starts inside a word.
2878 * Returns a pointer to just after the word.
2879 */
2880 char_u *
2881find_word_end(ptr)
2882 char_u *ptr;
2883{
2884#ifdef FEAT_MBYTE
2885 int start_class;
2886
2887 if (has_mbyte)
2888 {
2889 start_class = mb_get_class(ptr);
2890 if (start_class > 1)
2891 while (*ptr != NUL)
2892 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002893 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 if (mb_get_class(ptr) != start_class)
2895 break;
2896 }
2897 }
2898 else
2899#endif
2900 while (vim_iswordc(*ptr))
2901 ++ptr;
2902 return ptr;
2903}
2904
2905/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002906 * Find the end of the line, omitting CR and NL at the end.
2907 * Returns a pointer to just after the line.
2908 */
2909 static char_u *
2910find_line_end(ptr)
2911 char_u *ptr;
2912{
2913 char_u *s;
2914
2915 s = ptr + STRLEN(ptr);
2916 while (s > ptr && (s[-1] == CAR || s[-1] == NL))
2917 --s;
2918 return s;
2919}
2920
2921/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 * Free the list of completions
2923 */
2924 static void
2925ins_compl_free()
2926{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002927 compl_T *match;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002928 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002930 vim_free(compl_pattern);
2931 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002932 vim_free(compl_leader);
2933 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002935 if (compl_first_match == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002937
2938 ins_compl_del_pum();
2939 pum_clear();
2940
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002941 compl_curr_match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 do
2943 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002944 match = compl_curr_match;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002945 compl_curr_match = compl_curr_match->cp_next;
2946 vim_free(match->cp_str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 /* several entries may use the same fname, free it just once. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002948 if (match->cp_flags & FREE_FNAME)
2949 vim_free(match->cp_fname);
Bram Moolenaar39f05632006-03-19 22:15:26 +00002950 for (i = 0; i < CPT_COUNT; ++i)
2951 vim_free(match->cp_text[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 vim_free(match);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002953 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
2954 compl_first_match = compl_curr_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955}
2956
2957 static void
2958ins_compl_clear()
2959{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002960 compl_cont_status = 0;
2961 compl_started = FALSE;
2962 compl_matches = 0;
2963 vim_free(compl_pattern);
2964 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002965 vim_free(compl_leader);
2966 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 edit_submode_extra = NULL;
Bram Moolenaara94bc432006-03-10 21:42:59 +00002968 vim_free(compl_orig_text);
2969 compl_orig_text = NULL;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00002970 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971}
2972
2973/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002974 * Return TRUE when Insert completion is active.
2975 */
2976 int
2977ins_compl_active()
2978{
2979 return compl_started;
2980}
2981
2982/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002983 * Delete one character before the cursor and show the subset of the matches
2984 * that match the word that is now before the cursor.
Bram Moolenaarc1e37902006-04-18 21:55:01 +00002985 * Returns the character to be used, NUL if the work is done and another char
2986 * to be got from the user.
Bram Moolenaara6557602006-02-04 22:43:20 +00002987 */
2988 static int
2989ins_compl_bs()
2990{
2991 char_u *line;
2992 char_u *p;
2993
Bram Moolenaarc1e37902006-04-18 21:55:01 +00002994 line = ml_get_curline();
2995 p = line + curwin->w_cursor.col;
2996 mb_ptr_back(line, p);
2997
2998 /* Stop completion when the whole word was deleted. */
2999 if ((int)(p - line) - (int)compl_col <= 0)
3000 return K_BS;
3001
Bram Moolenaara6557602006-02-04 22:43:20 +00003002 if (curwin->w_cursor.col <= compl_col + compl_length)
3003 {
3004 /* Deleted more than what was used to find matches, need to look for
3005 * matches all over again. */
3006 ins_compl_free();
3007 compl_started = FALSE;
3008 compl_matches = 0;
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00003009 compl_cont_status = 0;
3010 compl_cont_mode = 0;
Bram Moolenaara6557602006-02-04 22:43:20 +00003011 }
3012
Bram Moolenaara6557602006-02-04 22:43:20 +00003013 vim_free(compl_leader);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003014 compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
Bram Moolenaara6557602006-02-04 22:43:20 +00003015 if (compl_leader != NULL)
3016 {
3017 ins_compl_del_pum();
3018 ins_compl_delete();
3019 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3020
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003021 if (compl_started)
3022 ins_compl_set_original_text(compl_leader);
3023 else
Bram Moolenaara6557602006-02-04 22:43:20 +00003024 {
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00003025#ifdef FEAT_SPELL
3026 spell_bad_len = 0; /* need to redetect bad word */
3027#endif
Bram Moolenaara6557602006-02-04 22:43:20 +00003028 /* Matches were cleared, need to search for them now. */
3029 if (ins_complete(Ctrl_N) == FAIL)
3030 compl_cont_status = 0;
3031 else
3032 {
3033 /* Remove the completed word again. */
3034 ins_compl_delete();
3035 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3036 }
3037 }
3038
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00003039 /* Go to the original text, since none of the matches is inserted. */
3040 if (compl_first_match->cp_prev != NULL
3041 && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT))
3042 compl_shown_match = compl_first_match->cp_prev;
3043 else
3044 compl_shown_match = compl_first_match;
3045 compl_curr_match = compl_shown_match;
3046 compl_shows_dir = compl_direction;
3047
Bram Moolenaara6557602006-02-04 22:43:20 +00003048 /* Show the popup menu with a different set of matches. */
3049 ins_compl_show_pum();
3050 compl_used_match = FALSE;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003051 compl_enter_selects = FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +00003052
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003053 return NUL;
Bram Moolenaara6557602006-02-04 22:43:20 +00003054 }
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003055 return K_BS;
Bram Moolenaara6557602006-02-04 22:43:20 +00003056}
3057
3058/*
3059 * Append one character to the match leader. May reduce the number of
3060 * matches.
3061 */
3062 static void
3063ins_compl_addleader(c)
3064 int c;
3065{
3066#ifdef FEAT_MBYTE
3067 int cc;
3068
3069 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
3070 {
3071 char_u buf[MB_MAXBYTES + 1];
3072
3073 (*mb_char2bytes)(c, buf);
3074 buf[cc] = NUL;
3075 ins_char_bytes(buf, cc);
3076 }
3077 else
3078#endif
3079 ins_char(c);
3080
3081 vim_free(compl_leader);
3082 compl_leader = vim_strnsave(ml_get_curline() + compl_col,
3083 curwin->w_cursor.col - compl_col);
3084 if (compl_leader != NULL)
3085 {
3086 /* Show the popup menu with a different set of matches. */
3087 ins_compl_del_pum();
3088 ins_compl_show_pum();
3089 compl_used_match = FALSE;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003090 compl_enter_selects = FALSE;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003091 ins_compl_set_original_text(compl_leader);
3092 }
3093}
3094
3095/*
3096 * Set the first match, the original text.
3097 */
3098 static void
3099ins_compl_set_original_text(str)
3100 char_u *str;
3101{
3102 char_u *p;
3103
3104 /* Replace the original text entry. */
3105 if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */
3106 {
3107 p = vim_strsave(str);
3108 if (p != NULL)
3109 {
3110 vim_free(compl_first_match->cp_str);
3111 compl_first_match->cp_str = p;
3112 }
Bram Moolenaara6557602006-02-04 22:43:20 +00003113 }
3114}
3115
3116/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003117 * Append one character to the match leader. May reduce the number of
3118 * matches.
3119 */
3120 static void
3121ins_compl_addfrommatch()
3122{
3123 char_u *p;
3124 int len = curwin->w_cursor.col - compl_col;
3125 int c;
3126
3127 p = compl_shown_match->cp_str;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00003128 if ((int)STRLEN(p) <= len) /* the match is too short */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003129 return;
3130 p += len;
3131#ifdef FEAT_MBYTE
3132 c = mb_ptr2char(p);
3133#else
3134 c = *p;
3135#endif
3136 ins_compl_addleader(c);
3137}
3138
3139/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140 * Prepare for Insert mode completion, or stop it.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003141 * Called just after typing a character in Insert mode.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003142 * Returns TRUE when the character is not to be inserted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003144 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145ins_compl_prep(c)
3146 int c;
3147{
3148 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 int temp;
3150 int want_cindent;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003151 int retval = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152
3153 /* Forget any previous 'special' messages if this is actually
3154 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
3155 */
3156 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
3157 edit_submode_extra = NULL;
3158
3159 /* Ignore end of Select mode mapping */
3160 if (c == K_SELECT)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003161 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003163 /* Set "compl_get_longest" when finding the first matches. */
3164 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
3165 || (ctrl_x_mode == 0 && !compl_started))
3166 {
3167 compl_get_longest = (vim_strchr(p_cot, 'l') != NULL);
3168 compl_used_match = TRUE;
3169 }
3170
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
3172 {
3173 /*
3174 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
3175 * it will be yet. Now we decide.
3176 */
3177 switch (c)
3178 {
3179 case Ctrl_E:
3180 case Ctrl_Y:
3181 ctrl_x_mode = CTRL_X_SCROLL;
3182 if (!(State & REPLACE_FLAG))
3183 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
3184 else
3185 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
3186 edit_submode_pre = NULL;
3187 showmode();
3188 break;
3189 case Ctrl_L:
3190 ctrl_x_mode = CTRL_X_WHOLE_LINE;
3191 break;
3192 case Ctrl_F:
3193 ctrl_x_mode = CTRL_X_FILES;
3194 break;
3195 case Ctrl_K:
3196 ctrl_x_mode = CTRL_X_DICTIONARY;
3197 break;
3198 case Ctrl_R:
3199 /* Simply allow ^R to happen without affecting ^X mode */
3200 break;
3201 case Ctrl_T:
3202 ctrl_x_mode = CTRL_X_THESAURUS;
3203 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003204#ifdef FEAT_COMPL_FUNC
3205 case Ctrl_U:
3206 ctrl_x_mode = CTRL_X_FUNCTION;
3207 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003208 case Ctrl_O:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003209 ctrl_x_mode = CTRL_X_OMNI;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003210 break;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003211#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003212 case 's':
3213 case Ctrl_S:
3214 ctrl_x_mode = CTRL_X_SPELL;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003215#ifdef FEAT_SPELL
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003216 ++emsg_off; /* Avoid getting the E756 error twice. */
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003217 spell_back_to_badword();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003218 --emsg_off;
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003219#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003220 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 case Ctrl_RSB:
3222 ctrl_x_mode = CTRL_X_TAGS;
3223 break;
3224#ifdef FEAT_FIND_ID
3225 case Ctrl_I:
3226 case K_S_TAB:
3227 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
3228 break;
3229 case Ctrl_D:
3230 ctrl_x_mode = CTRL_X_PATH_DEFINES;
3231 break;
3232#endif
3233 case Ctrl_V:
3234 case Ctrl_Q:
3235 ctrl_x_mode = CTRL_X_CMDLINE;
3236 break;
3237 case Ctrl_P:
3238 case Ctrl_N:
3239 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
3240 * just started ^X mode, or there were enough ^X's to cancel
3241 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
3242 * do normal expansion when interrupting a different mode (say
3243 * ^X^F^X^P or ^P^X^X^P, see below)
3244 * nothing changes if interrupting mode 0, (eg, the flag
3245 * doesn't change when going to ADDING mode -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003246 if (!(compl_cont_status & CONT_INTRPT))
3247 compl_cont_status |= CONT_LOCAL;
3248 else if (compl_cont_mode != 0)
3249 compl_cont_status &= ~CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250 /* FALLTHROUGH */
3251 default:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003252 /* If we have typed at least 2 ^X's... for modes != 0, we set
3253 * compl_cont_status = 0 (eg, as if we had just started ^X
3254 * mode).
3255 * For mode 0, we set "compl_cont_mode" to an impossible
3256 * value, in both cases ^X^X can be used to restart the same
3257 * mode (avoiding ADDING mode).
3258 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
3259 * 'complete' and local ^P expansions respectively.
3260 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
3261 * mode -- Acevedo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 if (c == Ctrl_X)
3263 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003264 if (compl_cont_mode != 0)
3265 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003267 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 }
3269 ctrl_x_mode = 0;
3270 edit_submode = NULL;
3271 showmode();
3272 break;
3273 }
3274 }
3275 else if (ctrl_x_mode != 0)
3276 {
3277 /* We're already in CTRL-X mode, do we stay in it? */
3278 if (!vim_is_ctrl_x_key(c))
3279 {
3280 if (ctrl_x_mode == CTRL_X_SCROLL)
3281 ctrl_x_mode = 0;
3282 else
3283 ctrl_x_mode = CTRL_X_FINISHED;
3284 edit_submode = NULL;
3285 }
3286 showmode();
3287 }
3288
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003289 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 {
3291 /* Show error message from attempted keyword completion (probably
3292 * 'Pattern not found') until another key is hit, then go back to
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003293 * showing what mode we are in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 showmode();
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003295 if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R
3296 && !ins_compl_pum_key(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297 || ctrl_x_mode == CTRL_X_FINISHED)
3298 {
3299 /* Get here when we have finished typing a sequence of ^N and
3300 * ^P or other completion characters in CTRL-X mode. Free up
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003301 * memory that was used, and make sure we can redo the insert. */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003302 if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003304 char_u *p;
3305
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 /*
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003307 * If any of the original typed text has been changed, eg when
3308 * ignorecase is set, we must add back-spaces to the redo
3309 * buffer. We add as few as necessary to delete just the part
3310 * of the original text that has changed.
3311 * When using the longest match, edited the match or used
3312 * CTRL-E then don't use the current match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003314 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
3315 ptr = compl_curr_match->cp_str;
3316 else if (compl_leader != NULL)
3317 ptr = compl_leader;
3318 else
3319 ptr = compl_orig_text;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003320 p = compl_orig_text;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003321 for (temp = 0; p[temp] != NUL && p[temp] == ptr[temp]; ++temp)
3322 ;
3323#ifdef FEAT_MBYTE
3324 if (temp > 0)
3325 temp -= (*mb_head_off)(compl_orig_text, p + temp);
3326#endif
3327 for (p += temp; *p != NUL; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 AppendCharToRedobuff(K_BS);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003329 AppendToRedobuffLit(ptr + temp, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 }
3331
3332#ifdef FEAT_CINDENT
3333 want_cindent = (can_cindent && cindent_on());
3334#endif
3335 /*
3336 * When completing whole lines: fix indent for 'cindent'.
3337 * Otherwise, break line if it's too long.
3338 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003339 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 {
3341#ifdef FEAT_CINDENT
3342 /* re-indent the current line */
3343 if (want_cindent)
3344 {
3345 do_c_expr_indent();
3346 want_cindent = FALSE; /* don't do it again */
3347 }
3348#endif
3349 }
3350 else
3351 {
3352 /* put the cursor on the last char, for 'tw' formatting */
3353 curwin->w_cursor.col--;
3354 if (stop_arrow() == OK)
3355 insertchar(NUL, 0, -1);
3356 curwin->w_cursor.col++;
3357 }
3358
3359 auto_format(FALSE, TRUE);
3360
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003361 /* If the popup menu is displayed pressing CTRL-Y means accepting
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003362 * the selection without inserting anything. When
3363 * compl_enter_selects is set the Enter key does the same. */
3364 if ((c == Ctrl_Y || (compl_enter_selects
3365 && (c == CAR || c == K_KENTER || c == NL)))
3366 && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003367 retval = TRUE;
3368
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003369 /* CTRL-E means completion is Ended, go back to the typed text. */
3370 if (c == Ctrl_E)
3371 {
3372 ins_compl_delete();
3373 if (compl_leader != NULL)
3374 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3375 else if (compl_first_match != NULL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003376 ins_bytes(compl_orig_text
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003377 + curwin->w_cursor.col - compl_col);
3378 retval = TRUE;
3379 }
3380
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 ins_compl_free();
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003382 compl_started = FALSE;
3383 compl_matches = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 msg_clr_cmdline(); /* necessary for "noshowmode" */
3385 ctrl_x_mode = 0;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003386 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 if (edit_submode != NULL)
3388 {
3389 edit_submode = NULL;
3390 showmode();
3391 }
3392
3393#ifdef FEAT_CINDENT
3394 /*
3395 * Indent now if a key was typed that is in 'cinkeys'.
3396 */
3397 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
3398 do_c_expr_indent();
3399#endif
3400 }
3401 }
3402
3403 /* reset continue_* if we left expansion-mode, if we stay they'll be
3404 * (re)set properly in ins_complete() */
3405 if (!vim_is_ctrl_x_key(c))
3406 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003407 compl_cont_status = 0;
3408 compl_cont_mode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003410
3411 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412}
3413
3414/*
3415 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
3416 * (depending on flag) starting from buf and looking for a non-scanned
3417 * buffer (other than curbuf). curbuf is special, if it is called with
3418 * buf=curbuf then it has to be the first call for a given flag/expansion.
3419 *
3420 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
3421 */
3422 static buf_T *
3423ins_compl_next_buf(buf, flag)
3424 buf_T *buf;
3425 int flag;
3426{
3427#ifdef FEAT_WINDOWS
3428 static win_T *wp;
3429#endif
3430
3431 if (flag == 'w') /* just windows */
3432 {
3433#ifdef FEAT_WINDOWS
3434 if (buf == curbuf) /* first call for this flag/expansion */
3435 wp = curwin;
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003436 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 && wp->w_buffer->b_scanned)
3438 ;
3439 buf = wp->w_buffer;
3440#else
3441 buf = curbuf;
3442#endif
3443 }
3444 else
3445 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
3446 * (unlisted buffers)
3447 * When completing whole lines skip unloaded buffers. */
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003448 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 && ((flag == 'U'
3450 ? buf->b_p_bl
3451 : (!buf->b_p_bl
3452 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003453 || buf->b_scanned))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 ;
3455 return buf;
3456}
3457
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003458#ifdef FEAT_COMPL_FUNC
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003459static void expand_by_function __ARGS((int type, char_u *base));
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003460
3461/*
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003462 * Execute user defined complete function 'completefunc' or 'omnifunc', and
Bram Moolenaare344bea2005-09-01 20:46:49 +00003463 * get matches in "matches".
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003464 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003465 static void
3466expand_by_function(type, base)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003467 int type; /* CTRL_X_OMNI or CTRL_X_FUNCTION */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003468 char_u *base;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003469{
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003470 list_T *matchlist;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003471 char_u *args[2];
Bram Moolenaare344bea2005-09-01 20:46:49 +00003472 char_u *funcname;
3473 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003474
Bram Moolenaare344bea2005-09-01 20:46:49 +00003475 funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
3476 if (*funcname == NUL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003477 return;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003478
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003479 /* Call 'completefunc' to obtain the list of matches. */
3480 args[0] = (char_u *)"0";
Bram Moolenaare344bea2005-09-01 20:46:49 +00003481 args[1] = base;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003482
Bram Moolenaare344bea2005-09-01 20:46:49 +00003483 pos = curwin->w_cursor;
3484 matchlist = call_func_retlist(funcname, 2, args, FALSE);
3485 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003486 if (matchlist == NULL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003487 return;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003488
Bram Moolenaara94bc432006-03-10 21:42:59 +00003489 ins_compl_add_list(matchlist);
3490 list_unref(matchlist);
3491}
3492#endif /* FEAT_COMPL_FUNC */
3493
Bram Moolenaar39f05632006-03-19 22:15:26 +00003494#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00003495/*
3496 * Add completions from a list.
Bram Moolenaara94bc432006-03-10 21:42:59 +00003497 */
3498 static void
3499ins_compl_add_list(list)
3500 list_T *list;
3501{
3502 listitem_T *li;
Bram Moolenaara94bc432006-03-10 21:42:59 +00003503 int dir = compl_direction;
3504
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003505 /* Go through the List with matches and add each of them. */
Bram Moolenaara94bc432006-03-10 21:42:59 +00003506 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003507 {
Bram Moolenaar39f05632006-03-19 22:15:26 +00003508 if (ins_compl_add_tv(&li->li_tv, dir) == OK)
3509 /* if dir was BACKWARD then honor it just once */
3510 dir = FORWARD;
Bram Moolenaar280f1262006-01-30 00:14:18 +00003511 else if (did_emsg)
3512 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003513 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003514}
Bram Moolenaar39f05632006-03-19 22:15:26 +00003515
3516/*
3517 * Add a match to the list of matches from a typeval_T.
3518 * If the given string is already in the list of completions, then return
3519 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
3520 * maybe because alloc() returns NULL, then FAIL is returned.
3521 */
3522 int
3523ins_compl_add_tv(tv, dir)
3524 typval_T *tv;
3525 int dir;
3526{
3527 char_u *word;
3528 int icase = p_ic;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003529 int dup = FALSE;
Bram Moolenaar39f05632006-03-19 22:15:26 +00003530 char_u *(cptext[CPT_COUNT]);
3531
3532 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
3533 {
3534 word = get_dict_string(tv->vval.v_dict, (char_u *)"word", FALSE);
3535 cptext[CPT_ABBR] = get_dict_string(tv->vval.v_dict,
3536 (char_u *)"abbr", FALSE);
3537 cptext[CPT_MENU] = get_dict_string(tv->vval.v_dict,
3538 (char_u *)"menu", FALSE);
3539 cptext[CPT_KIND] = get_dict_string(tv->vval.v_dict,
3540 (char_u *)"kind", FALSE);
3541 cptext[CPT_INFO] = get_dict_string(tv->vval.v_dict,
3542 (char_u *)"info", FALSE);
3543 if (get_dict_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL)
3544 icase = get_dict_number(tv->vval.v_dict, (char_u *)"icase");
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003545 if (get_dict_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
3546 dup = get_dict_number(tv->vval.v_dict, (char_u *)"dup");
Bram Moolenaar39f05632006-03-19 22:15:26 +00003547 }
3548 else
3549 {
3550 word = get_tv_string_chk(tv);
3551 vim_memset(cptext, 0, sizeof(cptext));
3552 }
3553 if (word == NULL || *word == NUL)
3554 return FAIL;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003555 return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, dup);
Bram Moolenaar39f05632006-03-19 22:15:26 +00003556}
Bram Moolenaara94bc432006-03-10 21:42:59 +00003557#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003558
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003559/*
3560 * Get the next expansion(s), using "compl_pattern".
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003561 * The search starts at position "ini" in curbuf and in the direction
3562 * compl_direction.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003563 * When "compl_started" is FALSE start at that position, otherwise continue
3564 * where we stopped searching before.
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003565 * This may return before finding all the matches.
3566 * Return the total number of matches or -1 if still unknown -- Acevedo
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 */
3568 static int
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003569ins_compl_get_exp(ini)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570 pos_T *ini;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571{
3572 static pos_T first_match_pos;
3573 static pos_T last_match_pos;
3574 static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003575 static int found_all = FALSE; /* Found all matches of a
3576 certain type. */
3577 static buf_T *ins_buf = NULL; /* buffer being scanned */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578
Bram Moolenaar572cb562005-08-05 21:35:02 +00003579 pos_T *pos;
3580 char_u **matches;
3581 int save_p_scs;
3582 int save_p_ws;
3583 int save_p_ic;
3584 int i;
3585 int num_matches;
3586 int len;
3587 int found_new_match;
3588 int type = ctrl_x_mode;
3589 char_u *ptr;
3590 char_u *dict = NULL;
3591 int dict_f = 0;
3592 compl_T *old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003594 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 {
3596 for (ins_buf = firstbuf; ins_buf != NULL; ins_buf = ins_buf->b_next)
3597 ins_buf->b_scanned = 0;
3598 found_all = FALSE;
3599 ins_buf = curbuf;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003600 e_cpt = (compl_cont_status & CONT_LOCAL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003601 ? (char_u *)"." : curbuf->b_p_cpt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 last_match_pos = first_match_pos = *ini;
3603 }
3604
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003605 old_match = compl_curr_match; /* remember the last current match */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003606 pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
3608 for (;;)
3609 {
3610 found_new_match = FAIL;
3611
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003612 /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613 * or if found_all says this entry is done. For ^X^L only use the
3614 * entries from 'complete' that look in loaded buffers. */
3615 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003616 && (!compl_started || found_all))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 {
3618 found_all = FALSE;
3619 while (*e_cpt == ',' || *e_cpt == ' ')
3620 e_cpt++;
3621 if (*e_cpt == '.' && !curbuf->b_scanned)
3622 {
3623 ins_buf = curbuf;
3624 first_match_pos = *ini;
3625 /* So that ^N can match word immediately after cursor */
3626 if (ctrl_x_mode == 0)
3627 dec(&first_match_pos);
3628 last_match_pos = first_match_pos;
3629 type = 0;
3630 }
3631 else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
3632 && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
3633 {
3634 /* Scan a buffer, but not the current one. */
3635 if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
3636 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003637 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 first_match_pos.col = last_match_pos.col = 0;
3639 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
3640 last_match_pos.lnum = 0;
3641 type = 0;
3642 }
3643 else /* unloaded buffer, scan like dictionary */
3644 {
3645 found_all = TRUE;
3646 if (ins_buf->b_fname == NULL)
3647 continue;
3648 type = CTRL_X_DICTIONARY;
3649 dict = ins_buf->b_fname;
3650 dict_f = DICT_EXACT;
3651 }
Bram Moolenaar555b2802005-05-19 21:08:39 +00003652 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 ins_buf->b_fname == NULL
3654 ? buf_spname(ins_buf)
3655 : ins_buf->b_sfname == NULL
3656 ? (char *)ins_buf->b_fname
3657 : (char *)ins_buf->b_sfname);
3658 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3659 }
3660 else if (*e_cpt == NUL)
3661 break;
3662 else
3663 {
3664 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3665 type = -1;
3666 else if (*e_cpt == 'k' || *e_cpt == 's')
3667 {
3668 if (*e_cpt == 'k')
3669 type = CTRL_X_DICTIONARY;
3670 else
3671 type = CTRL_X_THESAURUS;
3672 if (*++e_cpt != ',' && *e_cpt != NUL)
3673 {
3674 dict = e_cpt;
3675 dict_f = DICT_FIRST;
3676 }
3677 }
3678#ifdef FEAT_FIND_ID
3679 else if (*e_cpt == 'i')
3680 type = CTRL_X_PATH_PATTERNS;
3681 else if (*e_cpt == 'd')
3682 type = CTRL_X_PATH_DEFINES;
3683#endif
3684 else if (*e_cpt == ']' || *e_cpt == 't')
3685 {
3686 type = CTRL_X_TAGS;
3687 sprintf((char*)IObuff, _("Scanning tags."));
3688 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3689 }
3690 else
3691 type = -1;
3692
3693 /* in any case e_cpt is advanced to the next entry */
3694 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
3695
3696 found_all = TRUE;
3697 if (type == -1)
3698 continue;
3699 }
3700 }
3701
3702 switch (type)
3703 {
3704 case -1:
3705 break;
3706#ifdef FEAT_FIND_ID
3707 case CTRL_X_PATH_PATTERNS:
3708 case CTRL_X_PATH_DEFINES:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003709 find_pattern_in_path(compl_pattern, compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003710 (int)STRLEN(compl_pattern), FALSE, FALSE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 (type == CTRL_X_PATH_DEFINES
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003712 && !(compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
3714 (linenr_T)1, (linenr_T)MAXLNUM);
3715 break;
3716#endif
3717
3718 case CTRL_X_DICTIONARY:
3719 case CTRL_X_THESAURUS:
3720 ins_compl_dictionaries(
Bram Moolenaar0b238792006-03-02 22:49:12 +00003721 dict != NULL ? dict
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 : (type == CTRL_X_THESAURUS
3723 ? (*curbuf->b_p_tsr == NUL
3724 ? p_tsr
3725 : curbuf->b_p_tsr)
3726 : (*curbuf->b_p_dict == NUL
3727 ? p_dict
3728 : curbuf->b_p_dict)),
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003729 compl_pattern,
Bram Moolenaar0b238792006-03-02 22:49:12 +00003730 dict != NULL ? dict_f
3731 : 0, type == CTRL_X_THESAURUS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 dict = NULL;
3733 break;
3734
3735 case CTRL_X_TAGS:
3736 /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
3737 save_p_ic = p_ic;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003738 p_ic = ignorecase(compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739
3740 /* Find up to TAG_MANY matches. Avoids that an enourmous number
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003741 * of matches is found when compl_pattern is empty */
3742 if (find_tags(compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
3744 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
3745 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3746 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003747 ins_compl_add_matches(num_matches, matches, p_ic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748 }
3749 p_ic = save_p_ic;
3750 break;
3751
3752 case CTRL_X_FILES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003753 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
3755 {
3756
3757 /* May change home directory back to "~". */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003758 tilde_replace(compl_pattern, num_matches, matches);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003759 ins_compl_add_matches(num_matches, matches,
3760#ifdef CASE_INSENSITIVE_FILENAME
3761 TRUE
3762#else
3763 FALSE
3764#endif
3765 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766 }
3767 break;
3768
3769 case CTRL_X_CMDLINE:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003770 if (expand_cmdline(&compl_xp, compl_pattern,
3771 (int)STRLEN(compl_pattern),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 &num_matches, &matches) == EXPAND_OK)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003773 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 break;
3775
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003776#ifdef FEAT_COMPL_FUNC
3777 case CTRL_X_FUNCTION:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003778 case CTRL_X_OMNI:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003779 expand_by_function(type, compl_pattern);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003780 break;
3781#endif
3782
Bram Moolenaar488c6512005-08-11 20:09:58 +00003783 case CTRL_X_SPELL:
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003784#ifdef FEAT_SPELL
Bram Moolenaar488c6512005-08-11 20:09:58 +00003785 num_matches = expand_spelling(first_match_pos.lnum,
3786 first_match_pos.col, compl_pattern, &matches);
3787 if (num_matches > 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003788 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar488c6512005-08-11 20:09:58 +00003789#endif
3790 break;
3791
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792 default: /* normal ^P/^N and ^X^L */
3793 /*
3794 * If 'infercase' is set, don't use 'smartcase' here
3795 */
3796 save_p_scs = p_scs;
3797 if (ins_buf->b_p_inf)
3798 p_scs = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003799
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 /* buffers other than curbuf are scanned from the beginning or the
3801 * end but never from the middle, thus setting nowrapscan in this
3802 * buffers is a good idea, on the other hand, we always set
3803 * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
3804 save_p_ws = p_ws;
3805 if (ins_buf != curbuf)
3806 p_ws = FALSE;
3807 else if (*e_cpt == '.')
3808 p_ws = TRUE;
3809 for (;;)
3810 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003811 int flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003813 /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that
3814 * has added a word that was at the beginning of the line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003816 || (compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 found_new_match = search_for_exact_line(ins_buf, pos,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003818 compl_direction, compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 else
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003820 found_new_match = searchit(NULL, ins_buf, pos,
3821 compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003822 compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
Bram Moolenaara23ccb82006-02-27 00:08:02 +00003823 RE_LAST, (linenr_T)0);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003824 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003826 /* set "compl_started" even on fail */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003827 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 first_match_pos = *pos;
3829 last_match_pos = *pos;
3830 }
3831 else if (first_match_pos.lnum == last_match_pos.lnum
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003832 && first_match_pos.col == last_match_pos.col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833 found_new_match = FAIL;
3834 if (found_new_match == FAIL)
3835 {
3836 if (ins_buf == curbuf)
3837 found_all = TRUE;
3838 break;
3839 }
3840
3841 /* when ADDING, the text before the cursor matches, skip it */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003842 if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 && ini->lnum == pos->lnum
3844 && ini->col == pos->col)
3845 continue;
3846 ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
3847 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3848 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003849 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 {
3851 if (pos->lnum >= ins_buf->b_ml.ml_line_count)
3852 continue;
3853 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3854 if (!p_paste)
3855 ptr = skipwhite(ptr);
3856 }
3857 len = (int)STRLEN(ptr);
3858 }
3859 else
3860 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003861 char_u *tmp_ptr = ptr;
3862
3863 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003864 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003865 tmp_ptr += compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 /* Skip if already inside a word. */
3867 if (vim_iswordp(tmp_ptr))
3868 continue;
3869 /* Find start of next word. */
3870 tmp_ptr = find_word_start(tmp_ptr);
3871 }
3872 /* Find end of this word. */
3873 tmp_ptr = find_word_end(tmp_ptr);
3874 len = (int)(tmp_ptr - ptr);
3875
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003876 if ((compl_cont_status & CONT_ADDING)
3877 && len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878 {
3879 if (pos->lnum < ins_buf->b_ml.ml_line_count)
3880 {
3881 /* Try next line, if any. the new word will be
3882 * "join" as if the normal command "J" was used.
3883 * IOSIZE is always greater than
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003884 * compl_length, so the next STRNCPY always
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 * works -- Acevedo */
3886 STRNCPY(IObuff, ptr, len);
3887 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3888 tmp_ptr = ptr = skipwhite(ptr);
3889 /* Find start of next word. */
3890 tmp_ptr = find_word_start(tmp_ptr);
3891 /* Find end of next word. */
3892 tmp_ptr = find_word_end(tmp_ptr);
3893 if (tmp_ptr > ptr)
3894 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003895 if (*ptr != ')' && IObuff[len - 1] != TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003897 if (IObuff[len - 1] != ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 IObuff[len++] = ' ';
3899 /* IObuf =~ "\k.* ", thus len >= 2 */
3900 if (p_js
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003901 && (IObuff[len - 2] == '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 || (vim_strchr(p_cpo, CPO_JOINSP)
3903 == NULL
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003904 && (IObuff[len - 2] == '?'
3905 || IObuff[len - 2] == '!'))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 IObuff[len++] = ' ';
3907 }
3908 /* copy as much as posible of the new word */
3909 if (tmp_ptr - ptr >= IOSIZE - len)
3910 tmp_ptr = ptr + IOSIZE - len - 1;
3911 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3912 len += (int)(tmp_ptr - ptr);
Bram Moolenaar572cb562005-08-05 21:35:02 +00003913 flags |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003914 }
3915 IObuff[len] = NUL;
3916 ptr = IObuff;
3917 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003918 if (len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 continue;
3920 }
3921 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003922 if (ins_compl_add_infercase(ptr, len, p_ic,
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003923 ins_buf == curbuf ? NULL : ins_buf->b_sfname,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003924 0, flags) != NOTDONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925 {
3926 found_new_match = OK;
3927 break;
3928 }
3929 }
3930 p_scs = save_p_scs;
3931 p_ws = save_p_ws;
3932 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003933
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003934 /* check if compl_curr_match has changed, (e.g. other type of
3935 * expansion added somenthing) */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003936 if (type != 0 && compl_curr_match != old_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937 found_new_match = OK;
3938
3939 /* break the loop for specialized modes (use 'complete' just for the
3940 * generic ctrl_x_mode == 0) or when we've found a new match */
3941 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003942 || found_new_match != FAIL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003943 {
3944 if (got_int)
3945 break;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003946 /* Fill the popup menu as soon as possible. */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003947 if (pum_wanted() && type != -1)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003948 ins_compl_check_keys(0);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003949
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003950 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
3951 || compl_interrupted)
3952 break;
3953 compl_started = TRUE;
3954 }
3955 else
3956 {
3957 /* Mark a buffer scanned when it has been scanned completely */
3958 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
3959 ins_buf->b_scanned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003961 compl_started = FALSE;
3962 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003964 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965
3966 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
3967 && *e_cpt == NUL) /* Got to end of 'complete' */
3968 found_new_match = FAIL;
3969
3970 i = -1; /* total of matches, unknown */
3971 if (found_new_match == FAIL
3972 || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
3973 i = ins_compl_make_cyclic();
3974
3975 /* If several matches were added (FORWARD) or the search failed and has
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003976 * just been made cyclic then we have to move compl_curr_match to the next
3977 * or previous entry (if any) -- Acevedo */
Bram Moolenaara94bc432006-03-10 21:42:59 +00003978 compl_curr_match = compl_direction == FORWARD ? old_match->cp_next
3979 : old_match->cp_prev;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003980 if (compl_curr_match == NULL)
3981 compl_curr_match = old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982 return i;
3983}
3984
3985/* Delete the old text being completed. */
3986 static void
3987ins_compl_delete()
3988{
3989 int i;
3990
3991 /*
3992 * In insert mode: Delete the typed part.
3993 * In replace mode: Put the old characters back, if any.
3994 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003995 i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 backspace_until_column(i);
3997 changed_cline_bef_curs();
3998}
3999
4000/* Insert the new text being completed. */
4001 static void
4002ins_compl_insert()
4003{
Bram Moolenaar572cb562005-08-05 21:35:02 +00004004 ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00004005 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
4006 compl_used_match = FALSE;
4007 else
4008 compl_used_match = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009}
4010
4011/*
4012 * Fill in the next completion in the current direction.
Bram Moolenaar572cb562005-08-05 21:35:02 +00004013 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
4014 * get more completions. If it is FALSE, then we just do nothing when there
4015 * are no more completions in a given direction. The latter case is used when
4016 * we are still in the middle of finding completions, to allow browsing
4017 * through the ones found so far.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018 * Return the total number of matches, or -1 if still unknown -- webb.
4019 *
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004020 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
4021 * compl_shown_match here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 *
4023 * Note that this function may be called recursively once only. First with
Bram Moolenaar572cb562005-08-05 21:35:02 +00004024 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
4025 * calls this function with "allow_get_expansion" FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026 */
4027 static int
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004028ins_compl_next(allow_get_expansion, count, insert_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 int allow_get_expansion;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004030 int count; /* repeat completion this many times; should
4031 be at least 1 */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004032 int insert_match; /* Insert the newly selected match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033{
4034 int num_matches = -1;
4035 int i;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004036 int todo = count;
Bram Moolenaara6557602006-02-04 22:43:20 +00004037 compl_T *found_compl = NULL;
4038 int found_end = FALSE;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004039 int advance;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004041 if (compl_leader != NULL
4042 && (compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 {
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004044 /* Set "compl_shown_match" to the actually shown match, it may differ
4045 * when "compl_leader" is used to omit some of the matches. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004046 while (!ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004047 compl_leader, (int)STRLEN(compl_leader))
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004048 && compl_shown_match->cp_next != NULL
4049 && compl_shown_match->cp_next != compl_first_match)
4050 compl_shown_match = compl_shown_match->cp_next;
4051 }
4052
4053 if (allow_get_expansion && insert_match
4054 && (!compl_get_longest || compl_used_match))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 /* Delete old text to be replaced */
4056 ins_compl_delete();
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004057
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004058 /* When finding the longest common text we stick at the original text,
4059 * don't let CTRL-N or CTRL-P move to the first match. */
4060 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4061
Bram Moolenaare3226be2005-12-18 22:10:00 +00004062 /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4063 * around. */
4064 while (--todo >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065 {
Bram Moolenaare3226be2005-12-18 22:10:00 +00004066 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004068 if (compl_pending != 0)
4069 --compl_pending;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004070 compl_shown_match = compl_shown_match->cp_next;
Bram Moolenaara6557602006-02-04 22:43:20 +00004071 found_end = (compl_first_match != NULL
4072 && (compl_shown_match->cp_next == compl_first_match
4073 || compl_shown_match == compl_first_match));
Bram Moolenaare3226be2005-12-18 22:10:00 +00004074 }
4075 else if (compl_shows_dir == BACKWARD
4076 && compl_shown_match->cp_prev != NULL)
4077 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004078 if (compl_pending != 0)
4079 ++compl_pending;
Bram Moolenaara6557602006-02-04 22:43:20 +00004080 found_end = (compl_shown_match == compl_first_match);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004081 compl_shown_match = compl_shown_match->cp_prev;
Bram Moolenaara6557602006-02-04 22:43:20 +00004082 found_end |= (compl_shown_match == compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083 }
4084 else
Bram Moolenaare3226be2005-12-18 22:10:00 +00004085 {
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004086 if (advance)
4087 {
4088 if (compl_shows_dir == BACKWARD)
4089 --compl_pending;
4090 else
4091 ++compl_pending;
4092 }
Bram Moolenaara6557602006-02-04 22:43:20 +00004093 if (!allow_get_expansion)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004094 return -1;
Bram Moolenaara6557602006-02-04 22:43:20 +00004095
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00004096 num_matches = ins_compl_get_exp(&compl_startpos);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004097 if (compl_pending != 0 && compl_direction == compl_shows_dir
4098 && advance)
Bram Moolenaara6557602006-02-04 22:43:20 +00004099 compl_shown_match = compl_curr_match;
4100 found_end = FALSE;
4101 }
4102 if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
4103 && compl_leader != NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004104 && !ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004105 compl_leader, (int)STRLEN(compl_leader)))
Bram Moolenaara6557602006-02-04 22:43:20 +00004106 ++todo;
4107 else
4108 /* Remember a matching item. */
4109 found_compl = compl_shown_match;
4110
4111 /* Stop at the end of the list when we found a usable match. */
4112 if (found_end)
4113 {
4114 if (found_compl != NULL)
4115 {
4116 compl_shown_match = found_compl;
4117 break;
4118 }
4119 todo = 1; /* use first usable match after wrapping around */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004120 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 }
4122
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004123 /* Insert the text of the new completion, or the compl_leader. */
4124 if (insert_match)
4125 {
4126 if (!compl_get_longest || compl_used_match)
4127 ins_compl_insert();
4128 else
4129 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
4130 }
4131 else
4132 compl_used_match = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133
4134 if (!allow_get_expansion)
4135 {
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004136 /* may undisplay the popup menu first */
4137 ins_compl_upd_pum();
4138
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004139 /* redraw to show the user what was inserted */
4140 update_screen(0);
4141
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004142 /* display the updated popup menu */
4143 ins_compl_show_pum();
4144
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145 /* Delete old text to be replaced, since we're still searching and
4146 * don't want to match ourselves! */
4147 ins_compl_delete();
4148 }
4149
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004150 /* Enter will select a match when the match wasn't inserted and the popup
4151 * menu is visislbe. */
4152 compl_enter_selects = !insert_match && compl_match_array != NULL;
4153
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 /*
4155 * Show the file name for the match (if any)
4156 * Truncate the file name to avoid a wait for return.
4157 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004158 if (compl_shown_match->cp_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 {
4160 STRCPY(IObuff, "match in file ");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004161 i = (vim_strsize(compl_shown_match->cp_fname) + 16) - sc_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 if (i <= 0)
4163 i = 0;
4164 else
4165 STRCAT(IObuff, "<");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004166 STRCAT(IObuff, compl_shown_match->cp_fname + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 msg(IObuff);
4168 redraw_cmdline = FALSE; /* don't overwrite! */
4169 }
4170
4171 return num_matches;
4172}
4173
4174/*
4175 * Call this while finding completions, to check whether the user has hit a key
4176 * that should change the currently displayed completion, or exit completion
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004177 * mode. Also, when compl_pending is not zero, show a completion as soon as
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 * possible. -- webb
Bram Moolenaar572cb562005-08-05 21:35:02 +00004179 * "frequency" specifies out of how many calls we actually check.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180 */
4181 void
Bram Moolenaar572cb562005-08-05 21:35:02 +00004182ins_compl_check_keys(frequency)
4183 int frequency;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184{
4185 static int count = 0;
4186
4187 int c;
4188
4189 /* Don't check when reading keys from a script. That would break the test
4190 * scripts */
4191 if (using_script())
4192 return;
4193
4194 /* Only do this at regular intervals */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004195 if (++count < frequency)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 return;
4197 count = 0;
4198
4199 ++no_mapping;
4200 c = vpeekc_any();
4201 --no_mapping;
4202 if (c != NUL)
4203 {
4204 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
4205 {
4206 c = safe_vgetc(); /* Eat the character */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004207 compl_shows_dir = ins_compl_key2dir(c);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004208 (void)ins_compl_next(FALSE, ins_compl_key2count(c),
4209 c != K_UP && c != K_DOWN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210 }
4211 else if (c != Ctrl_R)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004212 compl_interrupted = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 }
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004214 if (compl_pending != 0 && !got_int)
4215 (void)ins_compl_next(FALSE, compl_pending > 0
4216 ? compl_pending : -compl_pending, TRUE);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004217}
4218
4219/*
4220 * Decide the direction of Insert mode complete from the key typed.
4221 * Returns BACKWARD or FORWARD.
4222 */
4223 static int
4224ins_compl_key2dir(c)
4225 int c;
4226{
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004227 if (c == Ctrl_P || c == Ctrl_L
4228 || (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP
4229 || c == K_S_UP || c == K_UP)))
Bram Moolenaare3226be2005-12-18 22:10:00 +00004230 return BACKWARD;
4231 return FORWARD;
4232}
4233
4234/*
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004235 * Return TRUE for keys that are used for completion only when the popup menu
4236 * is visible.
4237 */
4238 static int
4239ins_compl_pum_key(c)
4240 int c;
4241{
4242 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004243 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
4244 || c == K_UP || c == K_DOWN);
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004245}
4246
4247/*
Bram Moolenaare3226be2005-12-18 22:10:00 +00004248 * Decide the number of completions to move forward.
4249 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4250 */
4251 static int
4252ins_compl_key2count(c)
4253 int c;
4254{
4255 int h;
4256
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004257 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004258 {
4259 h = pum_get_height();
4260 if (h > 3)
4261 h -= 2; /* keep some context */
4262 return h;
4263 }
4264 return 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265}
4266
4267/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004268 * Return TRUE if completion with "c" should insert the match, FALSE if only
4269 * to change the currently selected completion.
4270 */
4271 static int
4272ins_compl_use_match(c)
4273 int c;
4274{
4275 switch (c)
4276 {
4277 case K_UP:
4278 case K_DOWN:
4279 case K_PAGEDOWN:
4280 case K_KPAGEDOWN:
4281 case K_S_DOWN:
4282 case K_PAGEUP:
4283 case K_KPAGEUP:
4284 case K_S_UP:
4285 return FALSE;
4286 }
4287 return TRUE;
4288}
4289
4290/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291 * Do Insert mode completion.
4292 * Called when character "c" was typed, which has a meaning for completion.
4293 * Returns OK if completion was done, FAIL if something failed (out of mem).
4294 */
4295 static int
4296ins_complete(c)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004297 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004299 char_u *line;
4300 int startcol = 0; /* column where searched text starts */
4301 colnr_T curs_col; /* cursor column */
4302 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303
Bram Moolenaare3226be2005-12-18 22:10:00 +00004304 compl_direction = ins_compl_key2dir(c);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004305 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306 {
4307 /* First time we hit ^N or ^P (in a row, I mean) */
4308
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 did_ai = FALSE;
4310#ifdef FEAT_SMARTINDENT
4311 did_si = FALSE;
4312 can_si = FALSE;
4313 can_si_back = FALSE;
4314#endif
4315 if (stop_arrow() == FAIL)
4316 return FAIL;
4317
4318 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004319 curs_col = curwin->w_cursor.col;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004320 compl_pending = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321
4322 /* if this same ctrl_x_mode has been interrupted use the text from
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004323 * "compl_startpos" to the cursor as a pattern to add a new word
4324 * instead of expand the one before the cursor, in word-wise if
4325 * "compl_startpos"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004326 * is not in the same line as the cursor then fix it (the line has
4327 * been split because it was longer than 'tw'). if SOL is set then
4328 * skip the previous pattern, a word at the beginning of the line has
4329 * been inserted, we'll look for that -- Acevedo. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004330 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4331 && compl_cont_mode == ctrl_x_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332 {
4333 /*
4334 * it is a continued search
4335 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004336 compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337 if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
4338 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4339 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004340 if (compl_startpos.lnum != curwin->w_cursor.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004342 /* line (probably) wrapped, set compl_startpos to the
4343 * first non_blank in the line, if it is not a wordchar
4344 * include it to get a better pattern, but then we don't
4345 * want the "\\<" prefix, check it bellow */
4346 compl_col = (colnr_T)(skipwhite(line) - line);
4347 compl_startpos.col = compl_col;
4348 compl_startpos.lnum = curwin->w_cursor.lnum;
4349 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 }
4351 else
4352 {
4353 /* S_IPOS was set when we inserted a word that was at the
4354 * beginning of the line, which means that we'll go to SOL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004355 * mode but first we need to redefine compl_startpos */
4356 if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004358 compl_cont_status |= CONT_SOL;
4359 compl_startpos.col = (colnr_T)(skipwhite(
4360 line + compl_length
4361 + compl_startpos.col) - line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004363 compl_col = compl_startpos.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004365 compl_length = curwin->w_cursor.col - (int)compl_col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004366 /* IObuff is used to add a "word from the next line" would we
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 * have enough space? just being paranoic */
4368#define MIN_SPACE 75
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004369 if (compl_length > (IOSIZE - MIN_SPACE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004371 compl_cont_status &= ~CONT_SOL;
4372 compl_length = (IOSIZE - MIN_SPACE);
4373 compl_col = curwin->w_cursor.col - compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004375 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4376 if (compl_length < 1)
4377 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 }
4379 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004380 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004382 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383 }
4384 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004385 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004387 if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004389 compl_cont_mode = ctrl_x_mode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004391 compl_cont_status = 0;
4392 compl_cont_status |= CONT_N_ADDS;
4393 compl_startpos = curwin->w_cursor;
4394 startcol = (int)curs_col;
4395 compl_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396 }
4397
4398 /* Work out completion pattern and original text -- webb */
4399 if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
4400 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004401 if ((compl_cont_status & CONT_SOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4403 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004404 if (!(compl_cont_status & CONT_ADDING))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004406 while (--startcol >= 0 && vim_isIDc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004408 compl_col += ++startcol;
4409 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 }
4411 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004412 compl_pattern = str_foldcase(line + compl_col,
4413 compl_length, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004415 compl_pattern = vim_strnsave(line + compl_col,
4416 compl_length);
4417 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 return FAIL;
4419 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004420 else if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004421 {
4422 char_u *prefix = (char_u *)"\\<";
4423
4424 /* we need 3 extra chars, 1 for the NUL and
4425 * 2 >= strlen(prefix) -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004426 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4427 compl_length) + 3);
4428 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004430 if (!vim_iswordp(line + compl_col)
4431 || (compl_col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 && (
4433#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004434 vim_iswordp(mb_prevptr(line, line + compl_col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004436 vim_iswordc(line[compl_col - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437#endif
4438 )))
4439 prefix = (char_u *)"";
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004440 STRCPY((char *)compl_pattern, prefix);
4441 (void)quote_meta(compl_pattern + STRLEN(prefix),
4442 line + compl_col, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004444 else if (--startcol < 0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004446 !vim_iswordp(mb_prevptr(line, line + startcol + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004448 !vim_iswordc(line[startcol])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449#endif
4450 )
4451 {
4452 /* Match any word of at least two chars */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004453 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4454 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004456 compl_col += curs_col;
4457 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458 }
4459 else
4460 {
4461#ifdef FEAT_MBYTE
4462 /* Search the point of change class of multibyte character
4463 * or not a word single byte character backward. */
4464 if (has_mbyte)
4465 {
4466 int base_class;
4467 int head_off;
4468
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004469 startcol -= (*mb_head_off)(line, line + startcol);
4470 base_class = mb_get_class(line + startcol);
4471 while (--startcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004473 head_off = (*mb_head_off)(line, line + startcol);
4474 if (base_class != mb_get_class(line + startcol
4475 - head_off))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004477 startcol -= head_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 }
4479 }
4480 else
4481#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004482 while (--startcol >= 0 && vim_iswordc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004484 compl_col += ++startcol;
4485 compl_length = (int)curs_col - startcol;
4486 if (compl_length == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 {
4488 /* Only match word with at least two chars -- webb
4489 * there's no need to call quote_meta,
4490 * alloc(7) is enough -- Acevedo
4491 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004492 compl_pattern = alloc(7);
4493 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004495 STRCPY((char *)compl_pattern, "\\<");
4496 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4497 STRCAT((char *)compl_pattern, "\\k");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 }
4499 else
4500 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004501 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4502 compl_length) + 3);
4503 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004505 STRCPY((char *)compl_pattern, "\\<");
4506 (void)quote_meta(compl_pattern + 2, line + compl_col,
4507 compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 }
4509 }
4510 }
4511 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4512 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004513 compl_col = (colnr_T)(skipwhite(line) - line);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004514 compl_length = (int)curs_col - (int)compl_col;
4515 if (compl_length < 0) /* cursor in indent: empty pattern */
4516 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004518 compl_pattern = str_foldcase(line + compl_col, compl_length,
4519 NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004521 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4522 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523 return FAIL;
4524 }
4525 else if (ctrl_x_mode == CTRL_X_FILES)
4526 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004527 while (--startcol >= 0 && vim_isfilec(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004529 compl_col += ++startcol;
4530 compl_length = (int)curs_col - startcol;
4531 compl_pattern = addstar(line + compl_col, compl_length,
4532 EXPAND_FILES);
4533 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 return FAIL;
4535 }
4536 else if (ctrl_x_mode == CTRL_X_CMDLINE)
4537 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004538 compl_pattern = vim_strnsave(line, curs_col);
4539 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004541 set_cmd_context(&compl_xp, compl_pattern,
4542 (int)STRLEN(compl_pattern), curs_col);
4543 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4544 || compl_xp.xp_context == EXPAND_NOTHING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004546 startcol = (int)(compl_xp.xp_pattern - compl_pattern);
4547 compl_col = startcol;
4548 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 }
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004550 else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004551 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00004552#ifdef FEAT_COMPL_FUNC
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004553 /*
Bram Moolenaare344bea2005-09-01 20:46:49 +00004554 * Call user defined function 'completefunc' with "a:findstart"
4555 * set to 1 to obtain the length of text to use for completion.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004556 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00004557 char_u *args[2];
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004558 int col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004559 char_u *funcname;
4560 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004561
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004562 /* Call 'completefunc' or 'omnifunc' and get pattern length as a
Bram Moolenaare344bea2005-09-01 20:46:49 +00004563 * string */
4564 funcname = ctrl_x_mode == CTRL_X_FUNCTION
4565 ? curbuf->b_p_cfu : curbuf->b_p_ofu;
4566 if (*funcname == NUL)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004567 {
4568 EMSG2(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
4569 ? "completefunc" : "omnifunc");
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004570 return FAIL;
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004571 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004572
4573 args[0] = (char_u *)"1";
Bram Moolenaare344bea2005-09-01 20:46:49 +00004574 args[1] = NULL;
4575 pos = curwin->w_cursor;
4576 col = call_func_retnr(funcname, 2, args, FALSE);
4577 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004578
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004579 if (col < 0)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004580 col = curs_col;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004581 compl_col = col;
4582 if ((colnr_T)compl_col > curs_col)
4583 compl_col = curs_col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004584
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004585 /* Setup variables for completion. Need to obtain "line" again,
4586 * it may have become invalid. */
4587 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004588 compl_length = curs_col - compl_col;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004589 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4590 if (compl_pattern == NULL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004591#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004592 return FAIL;
4593 }
Bram Moolenaar488c6512005-08-11 20:09:58 +00004594 else if (ctrl_x_mode == CTRL_X_SPELL)
4595 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00004596#ifdef FEAT_SPELL
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +00004597 if (spell_bad_len > 0)
4598 compl_col = curs_col - spell_bad_len;
4599 else
4600 compl_col = spell_word_start(startcol);
4601 if (compl_col >= (colnr_T)startcol)
Bram Moolenaar488c6512005-08-11 20:09:58 +00004602 return FAIL;
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00004603 spell_expand_check_cap(compl_col);
Bram Moolenaare2f98b92006-03-29 21:18:24 +00004604 /* Need to obtain "line" again, it may have become invalid. */
4605 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar488c6512005-08-11 20:09:58 +00004606 compl_length = (int)curs_col - compl_col;
4607 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4608 if (compl_pattern == NULL)
4609#endif
4610 return FAIL;
4611 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004612 else
4613 {
4614 EMSG2(_(e_intern2), "ins_complete()");
4615 return FAIL;
4616 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004618 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 {
4620 edit_submode_pre = (char_u *)_(" Adding");
4621 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4622 {
4623 /* Insert a new line, keep indentation but ignore 'comments' */
4624#ifdef FEAT_COMMENTS
4625 char_u *old = curbuf->b_p_com;
4626
4627 curbuf->b_p_com = (char_u *)"";
4628#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004629 compl_startpos.lnum = curwin->w_cursor.lnum;
4630 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 ins_eol('\r');
4632#ifdef FEAT_COMMENTS
4633 curbuf->b_p_com = old;
4634#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004635 compl_length = 0;
4636 compl_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 }
4638 }
4639 else
4640 {
4641 edit_submode_pre = NULL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004642 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643 }
4644
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004645 if (compl_cont_status & CONT_LOCAL)
4646 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647 else
4648 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
4649
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00004650 /* Always add completion for the original text. */
4651 vim_free(compl_orig_text);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004652 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
4653 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00004654 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004656 vim_free(compl_pattern);
4657 compl_pattern = NULL;
4658 vim_free(compl_orig_text);
4659 compl_orig_text = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660 return FAIL;
4661 }
4662
4663 /* showmode might reset the internal line pointers, so it must
4664 * be called before line = ml_get(), or when this address is no
4665 * longer needed. -- Acevedo.
4666 */
4667 edit_submode_extra = (char_u *)_("-- Searching...");
4668 edit_submode_highl = HLF_COUNT;
4669 showmode();
4670 edit_submode_extra = NULL;
4671 out_flush();
4672 }
4673
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004674 compl_shown_match = compl_curr_match;
4675 compl_shows_dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676
4677 /*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004678 * Find next match (and following matches).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679 */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004680 n = ins_compl_next(TRUE, ins_compl_key2count(c), ins_compl_use_match(c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004682 /* may undisplay the popup menu */
4683 ins_compl_upd_pum();
4684
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004685 if (n > 1) /* all matches have been found */
4686 compl_matches = n;
4687 compl_curr_match = compl_shown_match;
4688 compl_direction = compl_shows_dir;
4689 compl_interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690
4691 /* eat the ESC to avoid leaving insert mode */
4692 if (got_int && !global_busy)
4693 {
4694 (void)vgetc();
4695 got_int = FALSE;
4696 }
4697
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004698 /* we found no match if the list has only the "compl_orig_text"-entry */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004699 if (compl_first_match == compl_first_match->cp_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004701 edit_submode_extra = (compl_cont_status & CONT_ADDING)
4702 && compl_length > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
4704 edit_submode_highl = HLF_E;
4705 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
4706 * because we couldn't expand anything at first place, but if we used
4707 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
4708 * (such as M in M'exico) if not tried already. -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004709 if ( compl_length > 1
4710 || (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711 || (ctrl_x_mode != 0
4712 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
4713 && ctrl_x_mode != CTRL_X_PATH_DEFINES))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004714 compl_cont_status &= ~CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715 }
4716
Bram Moolenaar572cb562005-08-05 21:35:02 +00004717 if (compl_curr_match->cp_flags & CONT_S_IPOS)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004718 compl_cont_status |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004720 compl_cont_status &= ~CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721
4722 if (edit_submode_extra == NULL)
4723 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004724 if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725 {
4726 edit_submode_extra = (char_u *)_("Back at original");
4727 edit_submode_highl = HLF_W;
4728 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004729 else if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 {
4731 edit_submode_extra = (char_u *)_("Word from other line");
4732 edit_submode_highl = HLF_COUNT;
4733 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004734 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 {
4736 edit_submode_extra = (char_u *)_("The only match");
4737 edit_submode_highl = HLF_COUNT;
4738 }
4739 else
4740 {
4741 /* Update completion sequence number when needed. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004742 if (compl_curr_match->cp_number == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004744 int number = 0;
4745 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004747 if (compl_direction == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 {
4749 /* search backwards for the first valid (!= -1) number.
4750 * This should normally succeed already at the first loop
4751 * cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004752 for (match = compl_curr_match->cp_prev; match != NULL
4753 && match != compl_first_match;
4754 match = match->cp_prev)
4755 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004757 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758 break;
4759 }
4760 if (match != NULL)
4761 /* go up and assign all numbers which are not assigned
4762 * yet */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004763 for (match = match->cp_next;
4764 match != NULL && match->cp_number == -1;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004765 match = match->cp_next)
4766 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767 }
4768 else /* BACKWARD */
4769 {
4770 /* search forwards (upwards) for the first valid (!= -1)
4771 * number. This should normally succeed already at the
4772 * first loop cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004773 for (match = compl_curr_match->cp_next; match != NULL
4774 && match != compl_first_match;
4775 match = match->cp_next)
4776 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004778 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 break;
4780 }
4781 if (match != NULL)
4782 /* go down and assign all numbers which are not
4783 * assigned yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004784 for (match = match->cp_prev; match
4785 && match->cp_number == -1;
4786 match = match->cp_prev)
4787 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788 }
4789 }
4790
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004791 /* The match should always have a sequence number now, this is
4792 * just a safety check. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004793 if (compl_curr_match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 {
4795 /* Space for 10 text chars. + 2x10-digit no.s */
4796 static char_u match_ref[31];
4797
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004798 if (compl_matches > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 sprintf((char *)IObuff, _("match %d of %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004800 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004802 sprintf((char *)IObuff, _("match %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004803 compl_curr_match->cp_number);
Bram Moolenaarce0842a2005-07-18 21:58:11 +00004804 vim_strncpy(match_ref, IObuff, 30);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805 edit_submode_extra = match_ref;
4806 edit_submode_highl = HLF_R;
4807 if (dollar_vcol)
4808 curs_columns(FALSE);
4809 }
4810 }
4811 }
4812
4813 /* Show a message about what (completion) mode we're in. */
4814 showmode();
4815 if (edit_submode_extra != NULL)
4816 {
4817 if (!p_smd)
4818 msg_attr(edit_submode_extra,
4819 edit_submode_highl < HLF_COUNT
4820 ? hl_attr(edit_submode_highl) : 0);
4821 }
4822 else
4823 msg_clr_cmdline(); /* necessary for "noshowmode" */
4824
Bram Moolenaara94bc432006-03-10 21:42:59 +00004825 /* RedrawingDisabled may be set when invoked through complete(). */
4826 n = RedrawingDisabled;
4827 RedrawingDisabled = 0;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004828 ins_compl_show_pum();
Bram Moolenaara94bc432006-03-10 21:42:59 +00004829 setcursor();
4830 RedrawingDisabled = n;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004831
Bram Moolenaar071d4272004-06-13 20:20:40 +00004832 return OK;
4833}
4834
4835/*
4836 * Looks in the first "len" chars. of "src" for search-metachars.
4837 * If dest is not NULL the chars. are copied there quoting (with
4838 * a backslash) the metachars, and dest would be NUL terminated.
4839 * Returns the length (needed) of dest
4840 */
4841 static int
4842quote_meta(dest, src, len)
4843 char_u *dest;
4844 char_u *src;
4845 int len;
4846{
4847 int m;
4848
4849 for (m = len; --len >= 0; src++)
4850 {
4851 switch (*src)
4852 {
4853 case '.':
4854 case '*':
4855 case '[':
4856 if (ctrl_x_mode == CTRL_X_DICTIONARY
4857 || ctrl_x_mode == CTRL_X_THESAURUS)
4858 break;
4859 case '~':
4860 if (!p_magic) /* quote these only if magic is set */
4861 break;
4862 case '\\':
4863 if (ctrl_x_mode == CTRL_X_DICTIONARY
4864 || ctrl_x_mode == CTRL_X_THESAURUS)
4865 break;
4866 case '^': /* currently it's not needed. */
4867 case '$':
4868 m++;
4869 if (dest != NULL)
4870 *dest++ = '\\';
4871 break;
4872 }
4873 if (dest != NULL)
4874 *dest++ = *src;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004875# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 /* Copy remaining bytes of a multibyte character. */
4877 if (has_mbyte)
4878 {
4879 int i, mb_len;
4880
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004881 mb_len = (*mb_ptr2len)(src) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 if (mb_len > 0 && len >= mb_len)
4883 for (i = 0; i < mb_len; ++i)
4884 {
4885 --len;
4886 ++src;
4887 if (dest != NULL)
4888 *dest++ = *src;
4889 }
4890 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004891# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892 }
4893 if (dest != NULL)
4894 *dest = NUL;
4895
4896 return m;
4897}
4898#endif /* FEAT_INS_EXPAND */
4899
4900/*
4901 * Next character is interpreted literally.
4902 * A one, two or three digit decimal number is interpreted as its byte value.
4903 * If one or two digits are entered, the next character is given to vungetc().
4904 * For Unicode a character > 255 may be returned.
4905 */
4906 int
4907get_literal()
4908{
4909 int cc;
4910 int nc;
4911 int i;
4912 int hex = FALSE;
4913 int octal = FALSE;
4914#ifdef FEAT_MBYTE
4915 int unicode = 0;
4916#endif
4917
4918 if (got_int)
4919 return Ctrl_C;
4920
4921#ifdef FEAT_GUI
4922 /*
4923 * In GUI there is no point inserting the internal code for a special key.
4924 * It is more useful to insert the string "<KEY>" instead. This would
4925 * probably be useful in a text window too, but it would not be
4926 * vi-compatible (maybe there should be an option for it?) -- webb
4927 */
4928 if (gui.in_use)
4929 ++allow_keys;
4930#endif
4931#ifdef USE_ON_FLY_SCROLL
4932 dont_scroll = TRUE; /* disallow scrolling here */
4933#endif
4934 ++no_mapping; /* don't map the next key hits */
4935 cc = 0;
4936 i = 0;
4937 for (;;)
4938 {
4939 do
4940 nc = safe_vgetc();
4941 while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
4942 || nc == K_HOR_SCROLLBAR);
4943#ifdef FEAT_CMDL_INFO
4944 if (!(State & CMDLINE)
4945# ifdef FEAT_MBYTE
4946 && MB_BYTE2LEN_CHECK(nc) == 1
4947# endif
4948 )
4949 add_to_showcmd(nc);
4950#endif
4951 if (nc == 'x' || nc == 'X')
4952 hex = TRUE;
4953 else if (nc == 'o' || nc == 'O')
4954 octal = TRUE;
4955#ifdef FEAT_MBYTE
4956 else if (nc == 'u' || nc == 'U')
4957 unicode = nc;
4958#endif
4959 else
4960 {
4961 if (hex
4962#ifdef FEAT_MBYTE
4963 || unicode != 0
4964#endif
4965 )
4966 {
4967 if (!vim_isxdigit(nc))
4968 break;
4969 cc = cc * 16 + hex2nr(nc);
4970 }
4971 else if (octal)
4972 {
4973 if (nc < '0' || nc > '7')
4974 break;
4975 cc = cc * 8 + nc - '0';
4976 }
4977 else
4978 {
4979 if (!VIM_ISDIGIT(nc))
4980 break;
4981 cc = cc * 10 + nc - '0';
4982 }
4983
4984 ++i;
4985 }
4986
4987 if (cc > 255
4988#ifdef FEAT_MBYTE
4989 && unicode == 0
4990#endif
4991 )
4992 cc = 255; /* limit range to 0-255 */
4993 nc = 0;
4994
4995 if (hex) /* hex: up to two chars */
4996 {
4997 if (i >= 2)
4998 break;
4999 }
5000#ifdef FEAT_MBYTE
5001 else if (unicode) /* Unicode: up to four or eight chars */
5002 {
5003 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
5004 break;
5005 }
5006#endif
5007 else if (i >= 3) /* decimal or octal: up to three chars */
5008 break;
5009 }
5010 if (i == 0) /* no number entered */
5011 {
5012 if (nc == K_ZERO) /* NUL is stored as NL */
5013 {
5014 cc = '\n';
5015 nc = 0;
5016 }
5017 else
5018 {
5019 cc = nc;
5020 nc = 0;
5021 }
5022 }
5023
5024 if (cc == 0) /* NUL is stored as NL */
5025 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00005026#ifdef FEAT_MBYTE
5027 if (enc_dbcs && (cc & 0xff) == 0)
5028 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
5029 second byte will cause trouble! */
5030#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005031
5032 --no_mapping;
5033#ifdef FEAT_GUI
5034 if (gui.in_use)
5035 --allow_keys;
5036#endif
5037 if (nc)
5038 vungetc(nc);
5039 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
5040 return cc;
5041}
5042
5043/*
5044 * Insert character, taking care of special keys and mod_mask
5045 */
5046 static void
5047insert_special(c, allow_modmask, ctrlv)
5048 int c;
5049 int allow_modmask;
5050 int ctrlv; /* c was typed after CTRL-V */
5051{
5052 char_u *p;
5053 int len;
5054
5055 /*
5056 * Special function key, translate into "<Key>". Up to the last '>' is
5057 * inserted with ins_str(), so as not to replace characters in replace
5058 * mode.
5059 * Only use mod_mask for special keys, to avoid things like <S-Space>,
5060 * unless 'allow_modmask' is TRUE.
5061 */
5062#ifdef MACOS
5063 /* Command-key never produces a normal key */
5064 if (mod_mask & MOD_MASK_CMD)
5065 allow_modmask = TRUE;
5066#endif
5067 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
5068 {
5069 p = get_special_key_name(c, mod_mask);
5070 len = (int)STRLEN(p);
5071 c = p[len - 1];
5072 if (len > 2)
5073 {
5074 if (stop_arrow() == FAIL)
5075 return;
5076 p[len - 1] = NUL;
5077 ins_str(p);
Bram Moolenaarebefac62005-12-28 22:39:57 +00005078 AppendToRedobuffLit(p, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005079 ctrlv = FALSE;
5080 }
5081 }
5082 if (stop_arrow() == OK)
5083 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
5084}
5085
5086/*
5087 * Special characters in this context are those that need processing other
5088 * than the simple insertion that can be performed here. This includes ESC
5089 * which terminates the insert, and CR/NL which need special processing to
5090 * open up a new line. This routine tries to optimize insertions performed by
5091 * the "redo", "undo" or "put" commands, so it needs to know when it should
5092 * stop and defer processing to the "normal" mechanism.
5093 * '0' and '^' are special, because they can be followed by CTRL-D.
5094 */
5095#ifdef EBCDIC
5096# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
5097#else
5098# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
5099#endif
5100
5101#ifdef FEAT_MBYTE
5102# define WHITECHAR(cc) (vim_iswhite(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
5103#else
5104# define WHITECHAR(cc) vim_iswhite(cc)
5105#endif
5106
5107 void
5108insertchar(c, flags, second_indent)
5109 int c; /* character to insert or NUL */
5110 int flags; /* INSCHAR_FORMAT, etc. */
5111 int second_indent; /* indent for second line if >= 0 */
5112{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113 int textwidth;
5114#ifdef FEAT_COMMENTS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005117 int fo_ins_blank;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118
5119 textwidth = comp_textwidth(flags & INSCHAR_FORMAT);
5120 fo_ins_blank = has_format_option(FO_INS_BLANK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121
5122 /*
5123 * Try to break the line in two or more pieces when:
5124 * - Always do this if we have been called to do formatting only.
5125 * - Always do this when 'formatoptions' has the 'a' flag and the line
5126 * ends in white space.
5127 * - Otherwise:
5128 * - Don't do this if inserting a blank
5129 * - Don't do this if an existing character is being replaced, unless
5130 * we're in VREPLACE mode.
5131 * - Do this if the cursor is not on the line where insert started
5132 * or - 'formatoptions' doesn't have 'l' or the line was not too long
5133 * before the insert.
5134 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
5135 * before 'textwidth'
5136 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005137 if (textwidth > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138 && ((flags & INSCHAR_FORMAT)
5139 || (!vim_iswhite(c)
5140 && !((State & REPLACE_FLAG)
5141#ifdef FEAT_VREPLACE
5142 && !(State & VREPLACE_FLAG)
5143#endif
5144 && *ml_get_cursor() != NUL)
5145 && (curwin->w_cursor.lnum != Insstart.lnum
5146 || ((!has_format_option(FO_INS_LONG)
5147 || Insstart_textlen <= (colnr_T)textwidth)
5148 && (!fo_ins_blank
5149 || Insstart_blank_vcol <= (colnr_T)textwidth
5150 ))))))
5151 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005152 /* Format with 'formatexpr' when it's set. Use internal formatting
5153 * when 'formatexpr' isn't set or it returns non-zero. */
5154#if defined(FEAT_EVAL)
5155 if (*curbuf->b_p_fex == NUL
Bram Moolenaarf193fff2006-04-27 00:02:13 +00005156 || fex_format(curwin->w_cursor.lnum, 1L, c) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005158 internal_format(textwidth, second_indent, flags, c == NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005159 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005160
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161 if (c == NUL) /* only formatting was wanted */
5162 return;
5163
5164#ifdef FEAT_COMMENTS
5165 /* Check whether this character should end a comment. */
5166 if (did_ai && (int)c == end_comment_pending)
5167 {
5168 char_u *line;
5169 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
5170 int middle_len, end_len;
5171 int i;
5172
5173 /*
5174 * Need to remove existing (middle) comment leader and insert end
5175 * comment leader. First, check what comment leader we can find.
5176 */
5177 i = get_leader_len(line = ml_get_curline(), &p, FALSE);
5178 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
5179 {
5180 /* Skip middle-comment string */
5181 while (*p && p[-1] != ':') /* find end of middle flags */
5182 ++p;
5183 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5184 /* Don't count trailing white space for middle_len */
5185 while (middle_len > 0 && vim_iswhite(lead_end[middle_len - 1]))
5186 --middle_len;
5187
5188 /* Find the end-comment string */
5189 while (*p && p[-1] != ':') /* find end of end flags */
5190 ++p;
5191 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5192
5193 /* Skip white space before the cursor */
5194 i = curwin->w_cursor.col;
5195 while (--i >= 0 && vim_iswhite(line[i]))
5196 ;
5197 i++;
5198
5199 /* Skip to before the middle leader */
5200 i -= middle_len;
5201
5202 /* Check some expected things before we go on */
5203 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
5204 {
5205 /* Backspace over all the stuff we want to replace */
5206 backspace_until_column(i);
5207
5208 /*
5209 * Insert the end-comment string, except for the last
5210 * character, which will get inserted as normal later.
5211 */
5212 ins_bytes_len(lead_end, end_len - 1);
5213 }
5214 }
5215 }
5216 end_comment_pending = NUL;
5217#endif
5218
5219 did_ai = FALSE;
5220#ifdef FEAT_SMARTINDENT
5221 did_si = FALSE;
5222 can_si = FALSE;
5223 can_si_back = FALSE;
5224#endif
5225
5226 /*
5227 * If there's any pending input, grab up to INPUT_BUFLEN at once.
5228 * This speeds up normal text input considerably.
5229 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
5230 * need to re-indent at a ':', or any other character (but not what
5231 * 'paste' is set)..
5232 */
5233#ifdef USE_ON_FLY_SCROLL
5234 dont_scroll = FALSE; /* allow scrolling here */
5235#endif
5236
5237 if ( !ISSPECIAL(c)
5238#ifdef FEAT_MBYTE
5239 && (!has_mbyte || (*mb_char2len)(c) == 1)
5240#endif
5241 && vpeekc() != NUL
5242 && !(State & REPLACE_FLAG)
5243#ifdef FEAT_CINDENT
5244 && !cindent_on()
5245#endif
5246#ifdef FEAT_RIGHTLEFT
5247 && !p_ri
5248#endif
5249 )
5250 {
5251#define INPUT_BUFLEN 100
5252 char_u buf[INPUT_BUFLEN + 1];
5253 int i;
5254 colnr_T virtcol = 0;
5255
5256 buf[0] = c;
5257 i = 1;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005258 if (textwidth > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005259 virtcol = get_nolist_virtcol();
5260 /*
5261 * Stop the string when:
5262 * - no more chars available
5263 * - finding a special character (command key)
5264 * - buffer is full
5265 * - running into the 'textwidth' boundary
5266 * - need to check for abbreviation: A non-word char after a word-char
5267 */
5268 while ( (c = vpeekc()) != NUL
5269 && !ISSPECIAL(c)
5270#ifdef FEAT_MBYTE
5271 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
5272#endif
5273 && i < INPUT_BUFLEN
5274 && (textwidth == 0
5275 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
5276 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
5277 {
5278#ifdef FEAT_RIGHTLEFT
5279 c = vgetc();
5280 if (p_hkmap && KeyTyped)
5281 c = hkmap(c); /* Hebrew mode mapping */
5282# ifdef FEAT_FKMAP
5283 if (p_fkmap && KeyTyped)
5284 c = fkmap(c); /* Farsi mode mapping */
5285# endif
5286 buf[i++] = c;
5287#else
5288 buf[i++] = vgetc();
5289#endif
5290 }
5291
5292#ifdef FEAT_DIGRAPHS
5293 do_digraph(-1); /* clear digraphs */
5294 do_digraph(buf[i-1]); /* may be the start of a digraph */
5295#endif
5296 buf[i] = NUL;
5297 ins_str(buf);
5298 if (flags & INSCHAR_CTRLV)
5299 {
5300 redo_literal(*buf);
5301 i = 1;
5302 }
5303 else
5304 i = 0;
5305 if (buf[i] != NUL)
Bram Moolenaarebefac62005-12-28 22:39:57 +00005306 AppendToRedobuffLit(buf + i, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307 }
5308 else
5309 {
5310#ifdef FEAT_MBYTE
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005311 int cc;
5312
Bram Moolenaar071d4272004-06-13 20:20:40 +00005313 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
5314 {
5315 char_u buf[MB_MAXBYTES + 1];
5316
5317 (*mb_char2bytes)(c, buf);
5318 buf[cc] = NUL;
5319 ins_char_bytes(buf, cc);
5320 AppendCharToRedobuff(c);
5321 }
5322 else
5323#endif
5324 {
5325 ins_char(c);
5326 if (flags & INSCHAR_CTRLV)
5327 redo_literal(c);
5328 else
5329 AppendCharToRedobuff(c);
5330 }
5331 }
5332}
5333
5334/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005335 * Format text at the current insert position.
5336 */
5337 static void
5338internal_format(textwidth, second_indent, flags, format_only)
5339 int textwidth;
5340 int second_indent;
5341 int flags;
5342 int format_only;
5343{
5344 int cc;
5345 int save_char = NUL;
5346 int haveto_redraw = FALSE;
5347 int fo_ins_blank = has_format_option(FO_INS_BLANK);
5348#ifdef FEAT_MBYTE
5349 int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
5350#endif
5351 int fo_white_par = has_format_option(FO_WHITE_PAR);
5352 int first_line = TRUE;
5353#ifdef FEAT_COMMENTS
5354 colnr_T leader_len;
5355 int no_leader = FALSE;
5356 int do_comments = (flags & INSCHAR_DO_COM);
5357#endif
5358
5359 /*
5360 * When 'ai' is off we don't want a space under the cursor to be
5361 * deleted. Replace it with an 'x' temporarily.
5362 */
5363 if (!curbuf->b_p_ai)
5364 {
5365 cc = gchar_cursor();
5366 if (vim_iswhite(cc))
5367 {
5368 save_char = cc;
5369 pchar_cursor('x');
5370 }
5371 }
5372
5373 /*
5374 * Repeat breaking lines, until the current line is not too long.
5375 */
5376 while (!got_int)
5377 {
5378 int startcol; /* Cursor column at entry */
5379 int wantcol; /* column at textwidth border */
5380 int foundcol; /* column for start of spaces */
5381 int end_foundcol = 0; /* column for start of word */
5382 colnr_T len;
5383 colnr_T virtcol;
5384#ifdef FEAT_VREPLACE
5385 int orig_col = 0;
5386 char_u *saved_text = NULL;
5387#endif
5388 colnr_T col;
5389
5390 virtcol = get_nolist_virtcol();
5391 if (virtcol < (colnr_T)textwidth)
5392 break;
5393
5394#ifdef FEAT_COMMENTS
5395 if (no_leader)
5396 do_comments = FALSE;
5397 else if (!(flags & INSCHAR_FORMAT)
5398 && has_format_option(FO_WRAP_COMS))
5399 do_comments = TRUE;
5400
5401 /* Don't break until after the comment leader */
5402 if (do_comments)
5403 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE);
5404 else
5405 leader_len = 0;
5406
5407 /* If the line doesn't start with a comment leader, then don't
5408 * start one in a following broken line. Avoids that a %word
5409 * moved to the start of the next line causes all following lines
5410 * to start with %. */
5411 if (leader_len == 0)
5412 no_leader = TRUE;
5413#endif
5414 if (!(flags & INSCHAR_FORMAT)
5415#ifdef FEAT_COMMENTS
5416 && leader_len == 0
5417#endif
5418 && !has_format_option(FO_WRAP))
5419
5420 {
5421 textwidth = 0;
5422 break;
5423 }
5424 if ((startcol = curwin->w_cursor.col) == 0)
5425 break;
5426
5427 /* find column of textwidth border */
5428 coladvance((colnr_T)textwidth);
5429 wantcol = curwin->w_cursor.col;
5430
5431 curwin->w_cursor.col = startcol - 1;
5432#ifdef FEAT_MBYTE
5433 /* Correct cursor for multi-byte character. */
5434 if (has_mbyte)
5435 mb_adjust_cursor();
5436#endif
5437 foundcol = 0;
5438
5439 /*
5440 * Find position to break at.
5441 * Stop at first entered white when 'formatoptions' has 'v'
5442 */
5443 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
5444 || curwin->w_cursor.lnum != Insstart.lnum
5445 || curwin->w_cursor.col >= Insstart.col)
5446 {
5447 cc = gchar_cursor();
5448 if (WHITECHAR(cc))
5449 {
5450 /* remember position of blank just before text */
5451 end_foundcol = curwin->w_cursor.col;
5452
5453 /* find start of sequence of blanks */
5454 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
5455 {
5456 dec_cursor();
5457 cc = gchar_cursor();
5458 }
5459 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
5460 break; /* only spaces in front of text */
5461#ifdef FEAT_COMMENTS
5462 /* Don't break until after the comment leader */
5463 if (curwin->w_cursor.col < leader_len)
5464 break;
5465#endif
5466 if (has_format_option(FO_ONE_LETTER))
5467 {
5468 /* do not break after one-letter words */
5469 if (curwin->w_cursor.col == 0)
5470 break; /* one-letter word at begin */
5471
5472 col = curwin->w_cursor.col;
5473 dec_cursor();
5474 cc = gchar_cursor();
5475
5476 if (WHITECHAR(cc))
5477 continue; /* one-letter, continue */
5478 curwin->w_cursor.col = col;
5479 }
5480#ifdef FEAT_MBYTE
5481 if (has_mbyte)
5482 foundcol = curwin->w_cursor.col
5483 + (*mb_ptr2len)(ml_get_cursor());
5484 else
5485#endif
5486 foundcol = curwin->w_cursor.col + 1;
5487 if (curwin->w_cursor.col < (colnr_T)wantcol)
5488 break;
5489 }
5490#ifdef FEAT_MBYTE
5491 else if (cc >= 0x100 && fo_multibyte
5492 && curwin->w_cursor.col <= (colnr_T)wantcol)
5493 {
5494 /* Break after or before a multi-byte character. */
5495 foundcol = curwin->w_cursor.col;
5496 if (curwin->w_cursor.col < (colnr_T)wantcol)
5497 foundcol += (*mb_char2len)(cc);
5498 end_foundcol = foundcol;
5499 break;
5500 }
5501#endif
5502 if (curwin->w_cursor.col == 0)
5503 break;
5504 dec_cursor();
5505 }
5506
5507 if (foundcol == 0) /* no spaces, cannot break line */
5508 {
5509 curwin->w_cursor.col = startcol;
5510 break;
5511 }
5512
5513 /* Going to break the line, remove any "$" now. */
5514 undisplay_dollar();
5515
5516 /*
5517 * Offset between cursor position and line break is used by replace
5518 * stack functions. VREPLACE does not use this, and backspaces
5519 * over the text instead.
5520 */
5521#ifdef FEAT_VREPLACE
5522 if (State & VREPLACE_FLAG)
5523 orig_col = startcol; /* Will start backspacing from here */
5524 else
5525#endif
5526 replace_offset = startcol - end_foundcol - 1;
5527
5528 /*
5529 * adjust startcol for spaces that will be deleted and
5530 * characters that will remain on top line
5531 */
5532 curwin->w_cursor.col = foundcol;
5533 while (cc = gchar_cursor(), WHITECHAR(cc))
5534 inc_cursor();
5535 startcol -= curwin->w_cursor.col;
5536 if (startcol < 0)
5537 startcol = 0;
5538
5539#ifdef FEAT_VREPLACE
5540 if (State & VREPLACE_FLAG)
5541 {
5542 /*
5543 * In VREPLACE mode, we will backspace over the text to be
5544 * wrapped, so save a copy now to put on the next line.
5545 */
5546 saved_text = vim_strsave(ml_get_cursor());
5547 curwin->w_cursor.col = orig_col;
5548 if (saved_text == NULL)
5549 break; /* Can't do it, out of memory */
5550 saved_text[startcol] = NUL;
5551
5552 /* Backspace over characters that will move to the next line */
5553 if (!fo_white_par)
5554 backspace_until_column(foundcol);
5555 }
5556 else
5557#endif
5558 {
5559 /* put cursor after pos. to break line */
5560 if (!fo_white_par)
5561 curwin->w_cursor.col = foundcol;
5562 }
5563
5564 /*
5565 * Split the line just before the margin.
5566 * Only insert/delete lines, but don't really redraw the window.
5567 */
5568 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
5569 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
5570#ifdef FEAT_COMMENTS
5571 + (do_comments ? OPENLINE_DO_COM : 0)
5572#endif
5573 , old_indent);
5574 old_indent = 0;
5575
5576 replace_offset = 0;
5577 if (first_line)
5578 {
5579 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
5580 second_indent = get_number_indent(curwin->w_cursor.lnum -1);
5581 if (second_indent >= 0)
5582 {
5583#ifdef FEAT_VREPLACE
5584 if (State & VREPLACE_FLAG)
5585 change_indent(INDENT_SET, second_indent, FALSE, NUL);
5586 else
5587#endif
5588 (void)set_indent(second_indent, SIN_CHANGED);
5589 }
5590 first_line = FALSE;
5591 }
5592
5593#ifdef FEAT_VREPLACE
5594 if (State & VREPLACE_FLAG)
5595 {
5596 /*
5597 * In VREPLACE mode we have backspaced over the text to be
5598 * moved, now we re-insert it into the new line.
5599 */
5600 ins_bytes(saved_text);
5601 vim_free(saved_text);
5602 }
5603 else
5604#endif
5605 {
5606 /*
5607 * Check if cursor is not past the NUL off the line, cindent
5608 * may have added or removed indent.
5609 */
5610 curwin->w_cursor.col += startcol;
5611 len = (colnr_T)STRLEN(ml_get_curline());
5612 if (curwin->w_cursor.col > len)
5613 curwin->w_cursor.col = len;
5614 }
5615
5616 haveto_redraw = TRUE;
5617#ifdef FEAT_CINDENT
5618 can_cindent = TRUE;
5619#endif
5620 /* moved the cursor, don't autoindent or cindent now */
5621 did_ai = FALSE;
5622#ifdef FEAT_SMARTINDENT
5623 did_si = FALSE;
5624 can_si = FALSE;
5625 can_si_back = FALSE;
5626#endif
5627 line_breakcheck();
5628 }
5629
5630 if (save_char != NUL) /* put back space after cursor */
5631 pchar_cursor(save_char);
5632
5633 if (!format_only && haveto_redraw)
5634 {
5635 update_topline();
5636 redraw_curbuf_later(VALID);
5637 }
5638}
5639
5640/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005641 * Called after inserting or deleting text: When 'formatoptions' includes the
5642 * 'a' flag format from the current line until the end of the paragraph.
5643 * Keep the cursor at the same position relative to the text.
5644 * The caller must have saved the cursor line for undo, following ones will be
5645 * saved here.
5646 */
5647 void
5648auto_format(trailblank, prev_line)
5649 int trailblank; /* when TRUE also format with trailing blank */
5650 int prev_line; /* may start in previous line */
5651{
5652 pos_T pos;
5653 colnr_T len;
5654 char_u *old;
5655 char_u *new, *pnew;
5656 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005657 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658
5659 if (!has_format_option(FO_AUTO))
5660 return;
5661
5662 pos = curwin->w_cursor;
5663 old = ml_get_curline();
5664
5665 /* may remove added space */
5666 check_auto_format(FALSE);
5667
5668 /* Don't format in Insert mode when the cursor is on a trailing blank, the
5669 * user might insert normal text next. Also skip formatting when "1" is
5670 * in 'formatoptions' and there is a single character before the cursor.
5671 * Otherwise the line would be broken and when typing another non-white
5672 * next they are not joined back together. */
5673 wasatend = (pos.col == STRLEN(old));
5674 if (*old != NUL && !trailblank && wasatend)
5675 {
5676 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005677 cc = gchar_cursor();
5678 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
5679 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005681 cc = gchar_cursor();
5682 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005683 {
5684 curwin->w_cursor = pos;
5685 return;
5686 }
5687 curwin->w_cursor = pos;
5688 }
5689
5690#ifdef FEAT_COMMENTS
5691 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
5692 * comments. */
5693 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
5694 && get_leader_len(old, NULL, FALSE) == 0)
5695 return;
5696#endif
5697
5698 /*
5699 * May start formatting in a previous line, so that after "x" a word is
5700 * moved to the previous line if it fits there now. Only when this is not
5701 * the start of a paragraph.
5702 */
5703 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
5704 {
5705 --curwin->w_cursor.lnum;
5706 if (u_save_cursor() == FAIL)
5707 return;
5708 }
5709
5710 /*
5711 * Do the formatting and restore the cursor position. "saved_cursor" will
5712 * be adjusted for the text formatting.
5713 */
5714 saved_cursor = pos;
5715 format_lines((linenr_T)-1);
5716 curwin->w_cursor = saved_cursor;
5717 saved_cursor.lnum = 0;
5718
5719 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
5720 {
5721 /* "cannot happen" */
5722 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5723 coladvance((colnr_T)MAXCOL);
5724 }
5725 else
5726 check_cursor_col();
5727
5728 /* Insert mode: If the cursor is now after the end of the line while it
5729 * previously wasn't, the line was broken. Because of the rule above we
5730 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
5731 * formatted. */
5732 if (!wasatend && has_format_option(FO_WHITE_PAR))
5733 {
5734 new = ml_get_curline();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005735 len = (colnr_T)STRLEN(new);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736 if (curwin->w_cursor.col == len)
5737 {
5738 pnew = vim_strnsave(new, len + 2);
5739 pnew[len] = ' ';
5740 pnew[len + 1] = NUL;
5741 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
5742 /* remove the space later */
5743 did_add_space = TRUE;
5744 }
5745 else
5746 /* may remove added space */
5747 check_auto_format(FALSE);
5748 }
5749
5750 check_cursor();
5751}
5752
5753/*
5754 * When an extra space was added to continue a paragraph for auto-formatting,
5755 * delete it now. The space must be under the cursor, just after the insert
5756 * position.
5757 */
5758 static void
5759check_auto_format(end_insert)
5760 int end_insert; /* TRUE when ending Insert mode */
5761{
5762 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005763 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005764
5765 if (did_add_space)
5766 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005767 cc = gchar_cursor();
5768 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005769 /* Somehow the space was removed already. */
5770 did_add_space = FALSE;
5771 else
5772 {
5773 if (!end_insert)
5774 {
5775 inc_cursor();
5776 c = gchar_cursor();
5777 dec_cursor();
5778 }
5779 if (c != NUL)
5780 {
5781 /* The space is no longer at the end of the line, delete it. */
5782 del_char(FALSE);
5783 did_add_space = FALSE;
5784 }
5785 }
5786 }
5787}
5788
5789/*
5790 * Find out textwidth to be used for formatting:
5791 * if 'textwidth' option is set, use it
5792 * else if 'wrapmargin' option is set, use W_WIDTH(curwin) - 'wrapmargin'
5793 * if invalid value, use 0.
5794 * Set default to window width (maximum 79) for "gq" operator.
5795 */
5796 int
5797comp_textwidth(ff)
5798 int ff; /* force formatting (for "Q" command) */
5799{
5800 int textwidth;
5801
5802 textwidth = curbuf->b_p_tw;
5803 if (textwidth == 0 && curbuf->b_p_wm)
5804 {
5805 /* The width is the window width minus 'wrapmargin' minus all the
5806 * things that add to the margin. */
5807 textwidth = W_WIDTH(curwin) - curbuf->b_p_wm;
5808#ifdef FEAT_CMDWIN
5809 if (cmdwin_type != 0)
5810 textwidth -= 1;
5811#endif
5812#ifdef FEAT_FOLDING
5813 textwidth -= curwin->w_p_fdc;
5814#endif
5815#ifdef FEAT_SIGNS
5816 if (curwin->w_buffer->b_signlist != NULL
5817# ifdef FEAT_NETBEANS_INTG
5818 || usingNetbeans
5819# endif
5820 )
5821 textwidth -= 1;
5822#endif
5823 if (curwin->w_p_nu)
5824 textwidth -= 8;
5825 }
5826 if (textwidth < 0)
5827 textwidth = 0;
5828 if (ff && textwidth == 0)
5829 {
5830 textwidth = W_WIDTH(curwin) - 1;
5831 if (textwidth > 79)
5832 textwidth = 79;
5833 }
5834 return textwidth;
5835}
5836
5837/*
5838 * Put a character in the redo buffer, for when just after a CTRL-V.
5839 */
5840 static void
5841redo_literal(c)
5842 int c;
5843{
5844 char_u buf[10];
5845
5846 /* Only digits need special treatment. Translate them into a string of
5847 * three digits. */
5848 if (VIM_ISDIGIT(c))
5849 {
5850 sprintf((char *)buf, "%03d", c);
5851 AppendToRedobuff(buf);
5852 }
5853 else
5854 AppendCharToRedobuff(c);
5855}
5856
5857/*
5858 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005859 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860 */
5861 static void
5862start_arrow(end_insert_pos)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005863 pos_T *end_insert_pos; /* can be NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864{
5865 if (!arrow_used) /* something has been inserted */
5866 {
5867 AppendToRedobuff(ESC_STR);
5868 stop_insert(end_insert_pos, FALSE);
5869 arrow_used = TRUE; /* this means we stopped the current insert */
5870 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005871#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005872 check_spell_redraw();
5873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874}
5875
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005876#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005877/*
5878 * If we skipped highlighting word at cursor, do it now.
5879 * It may be skipped again, thus reset spell_redraw_lnum first.
5880 */
5881 static void
5882check_spell_redraw()
5883{
5884 if (spell_redraw_lnum != 0)
5885 {
5886 linenr_T lnum = spell_redraw_lnum;
5887
5888 spell_redraw_lnum = 0;
5889 redrawWinline(lnum, FALSE);
5890 }
5891}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005892
5893/*
5894 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
5895 * spelled word, if there is one.
5896 */
5897 static void
5898spell_back_to_badword()
5899{
5900 pos_T tpos = curwin->w_cursor;
5901
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00005902 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005903 if (curwin->w_cursor.col != tpos.col)
5904 start_arrow(&tpos);
5905}
Bram Moolenaar217ad922005-03-20 22:37:15 +00005906#endif
5907
Bram Moolenaar071d4272004-06-13 20:20:40 +00005908/*
5909 * stop_arrow() is called before a change is made in insert mode.
5910 * If an arrow key has been used, start a new insertion.
5911 * Returns FAIL if undo is impossible, shouldn't insert then.
5912 */
5913 int
5914stop_arrow()
5915{
5916 if (arrow_used)
5917 {
5918 if (u_save_cursor() == OK)
5919 {
5920 arrow_used = FALSE;
5921 ins_need_undo = FALSE;
5922 }
5923 Insstart = curwin->w_cursor; /* new insertion starts here */
5924 Insstart_textlen = linetabsize(ml_get_curline());
5925 ai_col = 0;
5926#ifdef FEAT_VREPLACE
5927 if (State & VREPLACE_FLAG)
5928 {
5929 orig_line_count = curbuf->b_ml.ml_line_count;
5930 vr_lines_changed = 1;
5931 }
5932#endif
5933 ResetRedobuff();
5934 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
Bram Moolenaara9b1e742005-12-19 22:14:58 +00005935 new_insert_skip = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936 }
5937 else if (ins_need_undo)
5938 {
5939 if (u_save_cursor() == OK)
5940 ins_need_undo = FALSE;
5941 }
5942
5943#ifdef FEAT_FOLDING
5944 /* Always open fold at the cursor line when inserting something. */
5945 foldOpenCursor();
5946#endif
5947
5948 return (arrow_used || ins_need_undo ? FAIL : OK);
5949}
5950
5951/*
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005952 * Do a few things to stop inserting.
5953 * "end_insert_pos" is where insert ended. It is NULL when we already jumped
5954 * to another window/buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005955 */
5956 static void
5957stop_insert(end_insert_pos, esc)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005958 pos_T *end_insert_pos;
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005959 int esc; /* called by ins_esc() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005960{
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005961 int cc;
5962 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005963
5964 stop_redo_ins();
5965 replace_flush(); /* abandon replace stack */
5966
5967 /*
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005968 * Save the inserted text for later redo with ^@ and CTRL-A.
5969 * Don't do it when "restart_edit" was set and nothing was inserted,
5970 * otherwise CTRL-O w and then <Left> will clear "last_insert".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005971 */
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005972 ptr = get_inserted();
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00005973 if (did_restart_edit == 0 || (ptr != NULL
5974 && (int)STRLEN(ptr) > new_insert_skip))
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005975 {
5976 vim_free(last_insert);
5977 last_insert = ptr;
5978 last_insert_skip = new_insert_skip;
5979 }
5980 else
5981 vim_free(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005983 if (!arrow_used && end_insert_pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005984 {
5985 /* Auto-format now. It may seem strange to do this when stopping an
5986 * insertion (or moving the cursor), but it's required when appending
5987 * a line and having it end in a space. But only do it when something
5988 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005989 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005990 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005991 pos_T tpos = curwin->w_cursor;
5992
Bram Moolenaar071d4272004-06-13 20:20:40 +00005993 /* When the cursor is at the end of the line after a space the
5994 * formatting will move it to the following word. Avoid that by
5995 * moving the cursor onto the space. */
5996 cc = 'x';
5997 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
5998 {
5999 dec_cursor();
6000 cc = gchar_cursor();
6001 if (!vim_iswhite(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006002 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003 }
6004
6005 auto_format(TRUE, FALSE);
6006
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006007 if (vim_iswhite(cc))
6008 {
6009 if (gchar_cursor() != NUL)
6010 inc_cursor();
6011#ifdef FEAT_VIRTUALEDIT
6012 /* If the cursor is still at the same character, also keep
6013 * the "coladd". */
6014 if (gchar_cursor() == NUL
6015 && curwin->w_cursor.lnum == tpos.lnum
6016 && curwin->w_cursor.col == tpos.col)
6017 curwin->w_cursor.coladd = tpos.coladd;
6018#endif
6019 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020 }
6021
6022 /* If a space was inserted for auto-formatting, remove it now. */
6023 check_auto_format(TRUE);
6024
6025 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006026 * of the line, and put the cursor back.
6027 * Do this when ESC was used or moving the cursor up/down. */
6028 if (did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006029 && curwin->w_cursor.lnum != end_insert_pos->lnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006030 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006031 pos_T tpos = curwin->w_cursor;
6032
6033 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar39f05632006-03-19 22:15:26 +00006034 for (;;)
6035 {
6036 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
6037 --curwin->w_cursor.col;
6038 cc = gchar_cursor();
6039 if (!vim_iswhite(cc))
6040 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041 (void)del_char(TRUE);
Bram Moolenaar39f05632006-03-19 22:15:26 +00006042 }
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006043 if (curwin->w_cursor.lnum != tpos.lnum)
6044 curwin->w_cursor = tpos;
6045 else if (cc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006046 ++curwin->w_cursor.col; /* put cursor back on the NUL */
6047
6048#ifdef FEAT_VISUAL
6049 /* <C-S-Right> may have started Visual mode, adjust the position for
6050 * deleted characters. */
6051 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
6052 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006053 cc = (int)STRLEN(ml_get_curline());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006054 if (VIsual.col > (colnr_T)cc)
6055 {
6056 VIsual.col = cc;
6057# ifdef FEAT_VIRTUALEDIT
6058 VIsual.coladd = 0;
6059# endif
6060 }
6061 }
6062#endif
6063 }
6064 }
6065 did_ai = FALSE;
6066#ifdef FEAT_SMARTINDENT
6067 did_si = FALSE;
6068 can_si = FALSE;
6069 can_si_back = FALSE;
6070#endif
6071
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006072 /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
6073 * now in a different buffer. */
6074 if (end_insert_pos != NULL)
6075 {
6076 curbuf->b_op_start = Insstart;
6077 curbuf->b_op_end = *end_insert_pos;
6078 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079}
6080
6081/*
6082 * Set the last inserted text to a single character.
6083 * Used for the replace command.
6084 */
6085 void
6086set_last_insert(c)
6087 int c;
6088{
6089 char_u *s;
6090
6091 vim_free(last_insert);
6092#ifdef FEAT_MBYTE
6093 last_insert = alloc(MB_MAXBYTES * 3 + 5);
6094#else
6095 last_insert = alloc(6);
6096#endif
6097 if (last_insert != NULL)
6098 {
6099 s = last_insert;
6100 /* Use the CTRL-V only when entering a special char */
6101 if (c < ' ' || c == DEL)
6102 *s++ = Ctrl_V;
6103 s = add_char2buf(c, s);
6104 *s++ = ESC;
6105 *s++ = NUL;
6106 last_insert_skip = 0;
6107 }
6108}
6109
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006110#if defined(EXITFREE) || defined(PROTO)
6111 void
6112free_last_insert()
6113{
6114 vim_free(last_insert);
6115 last_insert = NULL;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006116 vim_free(compl_orig_text);
6117 compl_orig_text = NULL;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006118}
6119#endif
6120
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121/*
6122 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
6123 * and CSI. Handle multi-byte characters.
6124 * Returns a pointer to after the added bytes.
6125 */
6126 char_u *
6127add_char2buf(c, s)
6128 int c;
6129 char_u *s;
6130{
6131#ifdef FEAT_MBYTE
6132 char_u temp[MB_MAXBYTES];
6133 int i;
6134 int len;
6135
6136 len = (*mb_char2bytes)(c, temp);
6137 for (i = 0; i < len; ++i)
6138 {
6139 c = temp[i];
6140#endif
6141 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
6142 if (c == K_SPECIAL)
6143 {
6144 *s++ = K_SPECIAL;
6145 *s++ = KS_SPECIAL;
6146 *s++ = KE_FILLER;
6147 }
6148#ifdef FEAT_GUI
6149 else if (c == CSI)
6150 {
6151 *s++ = CSI;
6152 *s++ = KS_EXTRA;
6153 *s++ = (int)KE_CSI;
6154 }
6155#endif
6156 else
6157 *s++ = c;
6158#ifdef FEAT_MBYTE
6159 }
6160#endif
6161 return s;
6162}
6163
6164/*
6165 * move cursor to start of line
6166 * if flags & BL_WHITE move to first non-white
6167 * if flags & BL_SOL move to first non-white if startofline is set,
6168 * otherwise keep "curswant" column
6169 * if flags & BL_FIX don't leave the cursor on a NUL.
6170 */
6171 void
6172beginline(flags)
6173 int flags;
6174{
6175 if ((flags & BL_SOL) && !p_sol)
6176 coladvance(curwin->w_curswant);
6177 else
6178 {
6179 curwin->w_cursor.col = 0;
6180#ifdef FEAT_VIRTUALEDIT
6181 curwin->w_cursor.coladd = 0;
6182#endif
6183
6184 if (flags & (BL_WHITE | BL_SOL))
6185 {
6186 char_u *ptr;
6187
6188 for (ptr = ml_get_curline(); vim_iswhite(*ptr)
6189 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
6190 ++curwin->w_cursor.col;
6191 }
6192 curwin->w_set_curswant = TRUE;
6193 }
6194}
6195
6196/*
6197 * oneright oneleft cursor_down cursor_up
6198 *
6199 * Move one char {right,left,down,up}.
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006200 * Doesn't move onto the NUL past the end of the line, unless it is allowed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006201 * Return OK when successful, FAIL when we hit a line of file boundary.
6202 */
6203
6204 int
6205oneright()
6206{
6207 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006209
6210#ifdef FEAT_VIRTUALEDIT
6211 if (virtual_active())
6212 {
6213 pos_T prevpos = curwin->w_cursor;
6214
6215 /* Adjust for multi-wide char (excluding TAB) */
6216 ptr = ml_get_cursor();
6217 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006218# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00006219 (*mb_ptr2char)(ptr)
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006220# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006221 *ptr
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006222# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223 ))
6224 ? ptr2cells(ptr) : 1));
6225 curwin->w_set_curswant = TRUE;
6226 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
6227 return (prevpos.col != curwin->w_cursor.col
6228 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
6229 }
6230#endif
6231
6232 ptr = ml_get_cursor();
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006233 if (*ptr == NUL)
6234 return FAIL; /* already at the very end */
6235
Bram Moolenaar071d4272004-06-13 20:20:40 +00006236#ifdef FEAT_MBYTE
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006237 if (has_mbyte)
6238 l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239 else
6240#endif
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006241 l = 1;
6242
6243 /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
6244 * contains "onemore". */
6245 if (ptr[l] == NUL
6246#ifdef FEAT_VIRTUALEDIT
6247 && (ve_flags & VE_ONEMORE) == 0
6248#endif
6249 )
6250 return FAIL;
6251 curwin->w_cursor.col += l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006252
6253 curwin->w_set_curswant = TRUE;
6254 return OK;
6255}
6256
6257 int
6258oneleft()
6259{
6260#ifdef FEAT_VIRTUALEDIT
6261 if (virtual_active())
6262 {
6263 int width;
6264 int v = getviscol();
6265
6266 if (v == 0)
6267 return FAIL;
6268
6269# ifdef FEAT_LINEBREAK
6270 /* We might get stuck on 'showbreak', skip over it. */
6271 width = 1;
6272 for (;;)
6273 {
6274 coladvance(v - width);
6275 /* getviscol() is slow, skip it when 'showbreak' is empty and
6276 * there are no multi-byte characters */
6277 if ((*p_sbr == NUL
6278# ifdef FEAT_MBYTE
6279 && !has_mbyte
6280# endif
6281 ) || getviscol() < v)
6282 break;
6283 ++width;
6284 }
6285# else
6286 coladvance(v - 1);
6287# endif
6288
6289 if (curwin->w_cursor.coladd == 1)
6290 {
6291 char_u *ptr;
6292
6293 /* Adjust for multi-wide char (not a TAB) */
6294 ptr = ml_get_cursor();
6295 if (*ptr != TAB && vim_isprintc(
6296# ifdef FEAT_MBYTE
6297 (*mb_ptr2char)(ptr)
6298# else
6299 *ptr
6300# endif
6301 ) && ptr2cells(ptr) > 1)
6302 curwin->w_cursor.coladd = 0;
6303 }
6304
6305 curwin->w_set_curswant = TRUE;
6306 return OK;
6307 }
6308#endif
6309
6310 if (curwin->w_cursor.col == 0)
6311 return FAIL;
6312
6313 curwin->w_set_curswant = TRUE;
6314 --curwin->w_cursor.col;
6315
6316#ifdef FEAT_MBYTE
6317 /* if the character on the left of the current cursor is a multi-byte
6318 * character, move to its first byte */
6319 if (has_mbyte)
6320 mb_adjust_cursor();
6321#endif
6322 return OK;
6323}
6324
6325 int
6326cursor_up(n, upd_topline)
6327 long n;
6328 int upd_topline; /* When TRUE: update topline */
6329{
6330 linenr_T lnum;
6331
6332 if (n > 0)
6333 {
6334 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00006335 /* This fails if the cursor is already in the first line or the count
6336 * is larger than the line number and '-' is in 'cpoptions' */
6337 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006338 return FAIL;
6339 if (n >= lnum)
6340 lnum = 1;
6341 else
6342#ifdef FEAT_FOLDING
6343 if (hasAnyFolding(curwin))
6344 {
6345 /*
6346 * Count each sequence of folded lines as one logical line.
6347 */
6348 /* go to the the start of the current fold */
6349 (void)hasFolding(lnum, &lnum, NULL);
6350
6351 while (n--)
6352 {
6353 /* move up one line */
6354 --lnum;
6355 if (lnum <= 1)
6356 break;
6357 /* If we entered a fold, move to the beginning, unless in
6358 * Insert mode or when 'foldopen' contains "all": it will open
6359 * in a moment. */
6360 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
6361 (void)hasFolding(lnum, &lnum, NULL);
6362 }
6363 if (lnum < 1)
6364 lnum = 1;
6365 }
6366 else
6367#endif
6368 lnum -= n;
6369 curwin->w_cursor.lnum = lnum;
6370 }
6371
6372 /* try to advance to the column we want to be at */
6373 coladvance(curwin->w_curswant);
6374
6375 if (upd_topline)
6376 update_topline(); /* make sure curwin->w_topline is valid */
6377
6378 return OK;
6379}
6380
6381/*
6382 * Cursor down a number of logical lines.
6383 */
6384 int
6385cursor_down(n, upd_topline)
6386 long n;
6387 int upd_topline; /* When TRUE: update topline */
6388{
6389 linenr_T lnum;
6390
6391 if (n > 0)
6392 {
6393 lnum = curwin->w_cursor.lnum;
6394#ifdef FEAT_FOLDING
6395 /* Move to last line of fold, will fail if it's the end-of-file. */
6396 (void)hasFolding(lnum, NULL, &lnum);
6397#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00006398 /* This fails if the cursor is already in the last line or would move
6399 * beyound the last line and '-' is in 'cpoptions' */
6400 if (lnum >= curbuf->b_ml.ml_line_count
6401 || (lnum + n > curbuf->b_ml.ml_line_count
6402 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006403 return FAIL;
6404 if (lnum + n >= curbuf->b_ml.ml_line_count)
6405 lnum = curbuf->b_ml.ml_line_count;
6406 else
6407#ifdef FEAT_FOLDING
6408 if (hasAnyFolding(curwin))
6409 {
6410 linenr_T last;
6411
6412 /* count each sequence of folded lines as one logical line */
6413 while (n--)
6414 {
6415 if (hasFolding(lnum, NULL, &last))
6416 lnum = last + 1;
6417 else
6418 ++lnum;
6419 if (lnum >= curbuf->b_ml.ml_line_count)
6420 break;
6421 }
6422 if (lnum > curbuf->b_ml.ml_line_count)
6423 lnum = curbuf->b_ml.ml_line_count;
6424 }
6425 else
6426#endif
6427 lnum += n;
6428 curwin->w_cursor.lnum = lnum;
6429 }
6430
6431 /* try to advance to the column we want to be at */
6432 coladvance(curwin->w_curswant);
6433
6434 if (upd_topline)
6435 update_topline(); /* make sure curwin->w_topline is valid */
6436
6437 return OK;
6438}
6439
6440/*
6441 * Stuff the last inserted text in the read buffer.
6442 * Last_insert actually is a copy of the redo buffer, so we
6443 * first have to remove the command.
6444 */
6445 int
6446stuff_inserted(c, count, no_esc)
6447 int c; /* Command character to be inserted */
6448 long count; /* Repeat this many times */
6449 int no_esc; /* Don't add an ESC at the end */
6450{
6451 char_u *esc_ptr;
6452 char_u *ptr;
6453 char_u *last_ptr;
6454 char_u last = NUL;
6455
6456 ptr = get_last_insert();
6457 if (ptr == NULL)
6458 {
6459 EMSG(_(e_noinstext));
6460 return FAIL;
6461 }
6462
6463 /* may want to stuff the command character, to start Insert mode */
6464 if (c != NUL)
6465 stuffcharReadbuff(c);
6466 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
6467 *esc_ptr = NUL; /* remove the ESC */
6468
6469 /* when the last char is either "0" or "^" it will be quoted if no ESC
6470 * comes after it OR if it will inserted more than once and "ptr"
6471 * starts with ^D. -- Acevedo
6472 */
6473 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
6474 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
6475 && (no_esc || (*ptr == Ctrl_D && count > 1)))
6476 {
6477 last = *last_ptr;
6478 *last_ptr = NUL;
6479 }
6480
6481 do
6482 {
6483 stuffReadbuff(ptr);
6484 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
6485 if (last)
6486 stuffReadbuff((char_u *)(last == '0'
6487 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
6488 : IF_EB("\026^", CTRL_V_STR "^")));
6489 }
6490 while (--count > 0);
6491
6492 if (last)
6493 *last_ptr = last;
6494
6495 if (esc_ptr != NULL)
6496 *esc_ptr = ESC; /* put the ESC back */
6497
6498 /* may want to stuff a trailing ESC, to get out of Insert mode */
6499 if (!no_esc)
6500 stuffcharReadbuff(ESC);
6501
6502 return OK;
6503}
6504
6505 char_u *
6506get_last_insert()
6507{
6508 if (last_insert == NULL)
6509 return NULL;
6510 return last_insert + last_insert_skip;
6511}
6512
6513/*
6514 * Get last inserted string, and remove trailing <Esc>.
6515 * Returns pointer to allocated memory (must be freed) or NULL.
6516 */
6517 char_u *
6518get_last_insert_save()
6519{
6520 char_u *s;
6521 int len;
6522
6523 if (last_insert == NULL)
6524 return NULL;
6525 s = vim_strsave(last_insert + last_insert_skip);
6526 if (s != NULL)
6527 {
6528 len = (int)STRLEN(s);
6529 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
6530 s[len - 1] = NUL;
6531 }
6532 return s;
6533}
6534
6535/*
6536 * Check the word in front of the cursor for an abbreviation.
6537 * Called when the non-id character "c" has been entered.
6538 * When an abbreviation is recognized it is removed from the text and
6539 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
6540 */
6541 static int
6542echeck_abbr(c)
6543 int c;
6544{
6545 /* Don't check for abbreviation in paste mode, when disabled and just
6546 * after moving around with cursor keys. */
6547 if (p_paste || no_abbr || arrow_used)
6548 return FALSE;
6549
6550 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
6551 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
6552}
6553
6554/*
6555 * replace-stack functions
6556 *
6557 * When replacing characters, the replaced characters are remembered for each
6558 * new character. This is used to re-insert the old text when backspacing.
6559 *
6560 * There is a NUL headed list of characters for each character that is
6561 * currently in the file after the insertion point. When BS is used, one NUL
6562 * headed list is put back for the deleted character.
6563 *
6564 * For a newline, there are two NUL headed lists. One contains the characters
6565 * that the NL replaced. The extra one stores the characters after the cursor
6566 * that were deleted (always white space).
6567 *
6568 * Replace_offset is normally 0, in which case replace_push will add a new
6569 * character at the end of the stack. If replace_offset is not 0, that many
6570 * characters will be left on the stack above the newly inserted character.
6571 */
6572
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00006573static char_u *replace_stack = NULL;
6574static long replace_stack_nr = 0; /* next entry in replace stack */
6575static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576
6577 void
6578replace_push(c)
6579 int c; /* character that is replaced (NUL is none) */
6580{
6581 char_u *p;
6582
6583 if (replace_stack_nr < replace_offset) /* nothing to do */
6584 return;
6585 if (replace_stack_len <= replace_stack_nr)
6586 {
6587 replace_stack_len += 50;
6588 p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
6589 if (p == NULL) /* out of memory */
6590 {
6591 replace_stack_len -= 50;
6592 return;
6593 }
6594 if (replace_stack != NULL)
6595 {
6596 mch_memmove(p, replace_stack,
6597 (size_t)(replace_stack_nr * sizeof(char_u)));
6598 vim_free(replace_stack);
6599 }
6600 replace_stack = p;
6601 }
6602 p = replace_stack + replace_stack_nr - replace_offset;
6603 if (replace_offset)
6604 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
6605 *p = c;
6606 ++replace_stack_nr;
6607}
6608
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006609#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006610/*
6611 * call replace_push(c) with replace_offset set to the first NUL.
6612 */
6613 static void
6614replace_push_off(c)
6615 int c;
6616{
6617 char_u *p;
6618
6619 p = replace_stack + replace_stack_nr;
6620 for (replace_offset = 1; replace_offset < replace_stack_nr;
6621 ++replace_offset)
6622 if (*--p == NUL)
6623 break;
6624 replace_push(c);
6625 replace_offset = 0;
6626}
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006627#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006628
6629/*
6630 * Pop one item from the replace stack.
6631 * return -1 if stack empty
6632 * return replaced character or NUL otherwise
6633 */
6634 static int
6635replace_pop()
6636{
6637 if (replace_stack_nr == 0)
6638 return -1;
6639 return (int)replace_stack[--replace_stack_nr];
6640}
6641
6642/*
6643 * Join the top two items on the replace stack. This removes to "off"'th NUL
6644 * encountered.
6645 */
6646 static void
6647replace_join(off)
6648 int off; /* offset for which NUL to remove */
6649{
6650 int i;
6651
6652 for (i = replace_stack_nr; --i >= 0; )
6653 if (replace_stack[i] == NUL && off-- <= 0)
6654 {
6655 --replace_stack_nr;
6656 mch_memmove(replace_stack + i, replace_stack + i + 1,
6657 (size_t)(replace_stack_nr - i));
6658 return;
6659 }
6660}
6661
6662/*
6663 * Pop bytes from the replace stack until a NUL is found, and insert them
6664 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
6665 */
6666 static void
6667replace_pop_ins()
6668{
6669 int cc;
6670 int oldState = State;
6671
6672 State = NORMAL; /* don't want REPLACE here */
6673 while ((cc = replace_pop()) > 0)
6674 {
6675#ifdef FEAT_MBYTE
6676 mb_replace_pop_ins(cc);
6677#else
6678 ins_char(cc);
6679#endif
6680 dec_cursor();
6681 }
6682 State = oldState;
6683}
6684
6685#ifdef FEAT_MBYTE
6686/*
6687 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
6688 * indicates a multi-byte char, pop the other bytes too.
6689 */
6690 static void
6691mb_replace_pop_ins(cc)
6692 int cc;
6693{
6694 int n;
6695 char_u buf[MB_MAXBYTES];
6696 int i;
6697 int c;
6698
6699 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
6700 {
6701 buf[0] = cc;
6702 for (i = 1; i < n; ++i)
6703 buf[i] = replace_pop();
6704 ins_bytes_len(buf, n);
6705 }
6706 else
6707 ins_char(cc);
6708
6709 if (enc_utf8)
6710 /* Handle composing chars. */
6711 for (;;)
6712 {
6713 c = replace_pop();
6714 if (c == -1) /* stack empty */
6715 break;
6716 if ((n = MB_BYTE2LEN(c)) == 1)
6717 {
6718 /* Not a multi-byte char, put it back. */
6719 replace_push(c);
6720 break;
6721 }
6722 else
6723 {
6724 buf[0] = c;
6725 for (i = 1; i < n; ++i)
6726 buf[i] = replace_pop();
6727 if (utf_iscomposing(utf_ptr2char(buf)))
6728 ins_bytes_len(buf, n);
6729 else
6730 {
6731 /* Not a composing char, put it back. */
6732 for (i = n - 1; i >= 0; --i)
6733 replace_push(buf[i]);
6734 break;
6735 }
6736 }
6737 }
6738}
6739#endif
6740
6741/*
6742 * make the replace stack empty
6743 * (called when exiting replace mode)
6744 */
6745 static void
6746replace_flush()
6747{
6748 vim_free(replace_stack);
6749 replace_stack = NULL;
6750 replace_stack_len = 0;
6751 replace_stack_nr = 0;
6752}
6753
6754/*
6755 * Handle doing a BS for one character.
6756 * cc < 0: replace stack empty, just move cursor
6757 * cc == 0: character was inserted, delete it
6758 * cc > 0: character was replaced, put cc (first byte of original char) back
6759 * and check for more characters to be put back
6760 */
6761 static void
6762replace_do_bs()
6763{
6764 int cc;
6765#ifdef FEAT_VREPLACE
6766 int orig_len = 0;
6767 int ins_len;
6768 int orig_vcols = 0;
6769 colnr_T start_vcol;
6770 char_u *p;
6771 int i;
6772 int vcol;
6773#endif
6774
6775 cc = replace_pop();
6776 if (cc > 0)
6777 {
6778#ifdef FEAT_VREPLACE
6779 if (State & VREPLACE_FLAG)
6780 {
6781 /* Get the number of screen cells used by the character we are
6782 * going to delete. */
6783 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
6784 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
6785 }
6786#endif
6787#ifdef FEAT_MBYTE
6788 if (has_mbyte)
6789 {
6790 del_char(FALSE);
6791# ifdef FEAT_VREPLACE
6792 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006793 orig_len = (int)STRLEN(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006794# endif
6795 replace_push(cc);
6796 }
6797 else
6798#endif
6799 {
6800 pchar_cursor(cc);
6801#ifdef FEAT_VREPLACE
6802 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006803 orig_len = (int)STRLEN(ml_get_cursor()) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006804#endif
6805 }
6806 replace_pop_ins();
6807
6808#ifdef FEAT_VREPLACE
6809 if (State & VREPLACE_FLAG)
6810 {
6811 /* Get the number of screen cells used by the inserted characters */
6812 p = ml_get_cursor();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006813 ins_len = (int)STRLEN(p) - orig_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006814 vcol = start_vcol;
6815 for (i = 0; i < ins_len; ++i)
6816 {
6817 vcol += chartabsize(p + i, vcol);
6818#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006819 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006820#endif
6821 }
6822 vcol -= start_vcol;
6823
6824 /* Delete spaces that were inserted after the cursor to keep the
6825 * text aligned. */
6826 curwin->w_cursor.col += ins_len;
6827 while (vcol > orig_vcols && gchar_cursor() == ' ')
6828 {
6829 del_char(FALSE);
6830 ++orig_vcols;
6831 }
6832 curwin->w_cursor.col -= ins_len;
6833 }
6834#endif
6835
6836 /* mark the buffer as changed and prepare for displaying */
6837 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
6838 }
6839 else if (cc == 0)
6840 (void)del_char(FALSE);
6841}
6842
6843#ifdef FEAT_CINDENT
6844/*
6845 * Return TRUE if C-indenting is on.
6846 */
6847 static int
6848cindent_on()
6849{
6850 return (!p_paste && (curbuf->b_p_cin
6851# ifdef FEAT_EVAL
6852 || *curbuf->b_p_inde != NUL
6853# endif
6854 ));
6855}
6856#endif
6857
6858#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
6859/*
6860 * Re-indent the current line, based on the current contents of it and the
6861 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
6862 * confused what all the part that handles Control-T is doing that I'm not.
6863 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
6864 */
6865
6866 void
6867fixthisline(get_the_indent)
6868 int (*get_the_indent) __ARGS((void));
6869{
6870 change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
6871 if (linewhite(curwin->w_cursor.lnum))
6872 did_ai = TRUE; /* delete the indent if the line stays empty */
6873}
6874
6875 void
6876fix_indent()
6877{
6878 if (p_paste)
6879 return;
6880# ifdef FEAT_LISP
6881 if (curbuf->b_p_lisp && curbuf->b_p_ai)
6882 fixthisline(get_lisp_indent);
6883# endif
6884# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
6885 else
6886# endif
6887# ifdef FEAT_CINDENT
6888 if (cindent_on())
6889 do_c_expr_indent();
6890# endif
6891}
6892
6893#endif
6894
6895#ifdef FEAT_CINDENT
6896/*
6897 * return TRUE if 'cinkeys' contains the key "keytyped",
6898 * when == '*': Only if key is preceded with '*' (indent before insert)
6899 * when == '!': Only if key is prededed with '!' (don't insert)
6900 * when == ' ': Only if key is not preceded with '*'(indent afterwards)
6901 *
6902 * "keytyped" can have a few special values:
6903 * KEY_OPEN_FORW
6904 * KEY_OPEN_BACK
6905 * KEY_COMPLETE just finished completion.
6906 *
6907 * If line_is_empty is TRUE accept keys with '0' before them.
6908 */
6909 int
6910in_cinkeys(keytyped, when, line_is_empty)
6911 int keytyped;
6912 int when;
6913 int line_is_empty;
6914{
6915 char_u *look;
6916 int try_match;
6917 int try_match_word;
6918 char_u *p;
6919 char_u *line;
6920 int icase;
6921 int i;
6922
6923#ifdef FEAT_EVAL
6924 if (*curbuf->b_p_inde != NUL)
6925 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
6926 else
6927#endif
6928 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
6929 while (*look)
6930 {
6931 /*
6932 * Find out if we want to try a match with this key, depending on
6933 * 'when' and a '*' or '!' before the key.
6934 */
6935 switch (when)
6936 {
6937 case '*': try_match = (*look == '*'); break;
6938 case '!': try_match = (*look == '!'); break;
6939 default: try_match = (*look != '*'); break;
6940 }
6941 if (*look == '*' || *look == '!')
6942 ++look;
6943
6944 /*
6945 * If there is a '0', only accept a match if the line is empty.
6946 * But may still match when typing last char of a word.
6947 */
6948 if (*look == '0')
6949 {
6950 try_match_word = try_match;
6951 if (!line_is_empty)
6952 try_match = FALSE;
6953 ++look;
6954 }
6955 else
6956 try_match_word = FALSE;
6957
6958 /*
6959 * does it look like a control character?
6960 */
6961 if (*look == '^'
6962#ifdef EBCDIC
6963 && (Ctrl_chr(look[1]) != 0)
6964#else
6965 && look[1] >= '?' && look[1] <= '_'
6966#endif
6967 )
6968 {
6969 if (try_match && keytyped == Ctrl_chr(look[1]))
6970 return TRUE;
6971 look += 2;
6972 }
6973 /*
6974 * 'o' means "o" command, open forward.
6975 * 'O' means "O" command, open backward.
6976 */
6977 else if (*look == 'o')
6978 {
6979 if (try_match && keytyped == KEY_OPEN_FORW)
6980 return TRUE;
6981 ++look;
6982 }
6983 else if (*look == 'O')
6984 {
6985 if (try_match && keytyped == KEY_OPEN_BACK)
6986 return TRUE;
6987 ++look;
6988 }
6989
6990 /*
6991 * 'e' means to check for "else" at start of line and just before the
6992 * cursor.
6993 */
6994 else if (*look == 'e')
6995 {
6996 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
6997 {
6998 p = ml_get_curline();
6999 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
7000 STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
7001 return TRUE;
7002 }
7003 ++look;
7004 }
7005
7006 /*
7007 * ':' only causes an indent if it is at the end of a label or case
7008 * statement, or when it was before typing the ':' (to fix
7009 * class::method for C++).
7010 */
7011 else if (*look == ':')
7012 {
7013 if (try_match && keytyped == ':')
7014 {
7015 p = ml_get_curline();
7016 if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
7017 return TRUE;
7018 if (curwin->w_cursor.col > 2
7019 && p[curwin->w_cursor.col - 1] == ':'
7020 && p[curwin->w_cursor.col - 2] == ':')
7021 {
7022 p[curwin->w_cursor.col - 1] = ' ';
7023 i = (cin_iscase(p) || cin_isscopedecl(p)
7024 || cin_islabel(30));
7025 p = ml_get_curline();
7026 p[curwin->w_cursor.col - 1] = ':';
7027 if (i)
7028 return TRUE;
7029 }
7030 }
7031 ++look;
7032 }
7033
7034
7035 /*
7036 * Is it a key in <>, maybe?
7037 */
7038 else if (*look == '<')
7039 {
7040 if (try_match)
7041 {
7042 /*
7043 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
7044 * <:> and <!> so that people can re-indent on o, O, e, 0, <,
7045 * >, *, : and ! keys if they really really want to.
7046 */
7047 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
7048 && keytyped == look[1])
7049 return TRUE;
7050
7051 if (keytyped == get_special_key_code(look + 1))
7052 return TRUE;
7053 }
7054 while (*look && *look != '>')
7055 look++;
7056 while (*look == '>')
7057 look++;
7058 }
7059
7060 /*
7061 * Is it a word: "=word"?
7062 */
7063 else if (*look == '=' && look[1] != ',' && look[1] != NUL)
7064 {
7065 ++look;
7066 if (*look == '~')
7067 {
7068 icase = TRUE;
7069 ++look;
7070 }
7071 else
7072 icase = FALSE;
7073 p = vim_strchr(look, ',');
7074 if (p == NULL)
7075 p = look + STRLEN(look);
7076 if ((try_match || try_match_word)
7077 && curwin->w_cursor.col >= (colnr_T)(p - look))
7078 {
7079 int match = FALSE;
7080
7081#ifdef FEAT_INS_EXPAND
7082 if (keytyped == KEY_COMPLETE)
7083 {
7084 char_u *s;
7085
7086 /* Just completed a word, check if it starts with "look".
7087 * search back for the start of a word. */
7088 line = ml_get_curline();
7089# ifdef FEAT_MBYTE
7090 if (has_mbyte)
7091 {
7092 char_u *n;
7093
7094 for (s = line + curwin->w_cursor.col; s > line; s = n)
7095 {
7096 n = mb_prevptr(line, s);
7097 if (!vim_iswordp(n))
7098 break;
7099 }
7100 }
7101 else
7102# endif
7103 for (s = line + curwin->w_cursor.col; s > line; --s)
7104 if (!vim_iswordc(s[-1]))
7105 break;
7106 if (s + (p - look) <= line + curwin->w_cursor.col
7107 && (icase
7108 ? MB_STRNICMP(s, look, p - look)
7109 : STRNCMP(s, look, p - look)) == 0)
7110 match = TRUE;
7111 }
7112 else
7113#endif
7114 /* TODO: multi-byte */
7115 if (keytyped == (int)p[-1] || (icase && keytyped < 256
7116 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
7117 {
7118 line = ml_get_cursor();
7119 if ((curwin->w_cursor.col == (colnr_T)(p - look)
7120 || !vim_iswordc(line[-(p - look) - 1]))
7121 && (icase
7122 ? MB_STRNICMP(line - (p - look), look, p - look)
7123 : STRNCMP(line - (p - look), look, p - look))
7124 == 0)
7125 match = TRUE;
7126 }
7127 if (match && try_match_word && !try_match)
7128 {
7129 /* "0=word": Check if there are only blanks before the
7130 * word. */
7131 line = ml_get_curline();
7132 if ((int)(skipwhite(line) - line) !=
7133 (int)(curwin->w_cursor.col - (p - look)))
7134 match = FALSE;
7135 }
7136 if (match)
7137 return TRUE;
7138 }
7139 look = p;
7140 }
7141
7142 /*
7143 * ok, it's a boring generic character.
7144 */
7145 else
7146 {
7147 if (try_match && *look == keytyped)
7148 return TRUE;
7149 ++look;
7150 }
7151
7152 /*
7153 * Skip over ", ".
7154 */
7155 look = skip_to_option_part(look);
7156 }
7157 return FALSE;
7158}
7159#endif /* FEAT_CINDENT */
7160
7161#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
7162/*
7163 * Map Hebrew keyboard when in hkmap mode.
7164 */
7165 int
7166hkmap(c)
7167 int c;
7168{
7169 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
7170 {
7171 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
7172 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
7173 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
7174 static char_u map[26] =
7175 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
7176 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
7177 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
7178 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
7179 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
7180 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
7181 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
7182 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
7183 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
7184
7185 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
7186 return (int)(map[CharOrd(c)] - 1 + p_aleph);
7187 /* '-1'='sofit' */
7188 else if (c == 'x')
7189 return 'X';
7190 else if (c == 'q')
7191 return '\''; /* {geresh}={'} */
7192 else if (c == 246)
7193 return ' '; /* \"o --> ' ' for a german keyboard */
7194 else if (c == 228)
7195 return ' '; /* \"a --> ' ' -- / -- */
7196 else if (c == 252)
7197 return ' '; /* \"u --> ' ' -- / -- */
7198#ifdef EBCDIC
7199 else if (islower(c))
7200#else
7201 /* NOTE: islower() does not do the right thing for us on Linux so we
7202 * do this the same was as 5.7 and previous, so it works correctly on
7203 * all systems. Specifically, the e.g. Delete and Arrow keys are
7204 * munged and won't work if e.g. searching for Hebrew text.
7205 */
7206 else if (c >= 'a' && c <= 'z')
7207#endif
7208 return (int)(map[CharOrdLow(c)] + p_aleph);
7209 else
7210 return c;
7211 }
7212 else
7213 {
7214 switch (c)
7215 {
7216 case '`': return ';';
7217 case '/': return '.';
7218 case '\'': return ',';
7219 case 'q': return '/';
7220 case 'w': return '\'';
7221
7222 /* Hebrew letters - set offset from 'a' */
7223 case ',': c = '{'; break;
7224 case '.': c = 'v'; break;
7225 case ';': c = 't'; break;
7226 default: {
7227 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
7228
7229#ifdef EBCDIC
7230 /* see note about islower() above */
7231 if (!islower(c))
7232#else
7233 if (c < 'a' || c > 'z')
7234#endif
7235 return c;
7236 c = str[CharOrdLow(c)];
7237 break;
7238 }
7239 }
7240
7241 return (int)(CharOrdLow(c) + p_aleph);
7242 }
7243}
7244#endif
7245
7246 static void
7247ins_reg()
7248{
7249 int need_redraw = FALSE;
7250 int regname;
7251 int literally = 0;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007252#ifdef FEAT_VISUAL
7253 int vis_active = VIsual_active;
7254#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007255
7256 /*
7257 * If we are going to wait for a character, show a '"'.
7258 */
7259 pc_status = PC_STATUS_UNSET;
7260 if (redrawing() && !char_avail())
7261 {
7262 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007263 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007264
7265 edit_putchar('"', TRUE);
7266#ifdef FEAT_CMDL_INFO
7267 add_to_showcmd_c(Ctrl_R);
7268#endif
7269 }
7270
7271#ifdef USE_ON_FLY_SCROLL
7272 dont_scroll = TRUE; /* disallow scrolling here */
7273#endif
7274
7275 /*
7276 * Don't map the register name. This also prevents the mode message to be
7277 * deleted when ESC is hit.
7278 */
7279 ++no_mapping;
7280 regname = safe_vgetc();
7281#ifdef FEAT_LANGMAP
7282 LANGMAP_ADJUST(regname, TRUE);
7283#endif
7284 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
7285 {
7286 /* Get a third key for literal register insertion */
7287 literally = regname;
7288#ifdef FEAT_CMDL_INFO
7289 add_to_showcmd_c(literally);
7290#endif
7291 regname = safe_vgetc();
7292#ifdef FEAT_LANGMAP
7293 LANGMAP_ADJUST(regname, TRUE);
7294#endif
7295 }
7296 --no_mapping;
7297
7298#ifdef FEAT_EVAL
7299 /*
7300 * Don't call u_sync() while getting the expression,
7301 * evaluating it or giving an error message for it!
7302 */
7303 ++no_u_sync;
7304 if (regname == '=')
7305 {
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007306# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007307 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007308# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007309 regname = get_expr_register();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007310# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007311 /* Restore the Input Method. */
7312 if (im_on)
7313 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007314# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007315 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00007316 if (regname == NUL || !valid_yank_reg(regname, FALSE))
7317 {
7318 vim_beep();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007319 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00007320 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007321 else
7322 {
7323#endif
7324 if (literally == Ctrl_O || literally == Ctrl_P)
7325 {
7326 /* Append the command to the redo buffer. */
7327 AppendCharToRedobuff(Ctrl_R);
7328 AppendCharToRedobuff(literally);
7329 AppendCharToRedobuff(regname);
7330
7331 do_put(regname, BACKWARD, 1L,
7332 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
7333 }
7334 else if (insert_reg(regname, literally) == FAIL)
7335 {
7336 vim_beep();
7337 need_redraw = TRUE; /* remove the '"' */
7338 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007339 else if (stop_insert_mode)
7340 /* When the '=' register was used and a function was invoked that
7341 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
7342 * insert anything, need to remove the '"' */
7343 need_redraw = TRUE;
7344
Bram Moolenaar071d4272004-06-13 20:20:40 +00007345#ifdef FEAT_EVAL
7346 }
7347 --no_u_sync;
7348#endif
7349#ifdef FEAT_CMDL_INFO
7350 clear_showcmd();
7351#endif
7352
7353 /* If the inserted register is empty, we need to remove the '"' */
7354 if (need_redraw || stuff_empty())
7355 edit_unputchar();
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007356
7357#ifdef FEAT_VISUAL
7358 /* Disallow starting Visual mode here, would get a weird mode. */
7359 if (!vis_active && VIsual_active)
7360 end_visual_mode();
7361#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007362}
7363
7364/*
7365 * CTRL-G commands in Insert mode.
7366 */
7367 static void
7368ins_ctrl_g()
7369{
7370 int c;
7371
7372#ifdef FEAT_INS_EXPAND
7373 /* Right after CTRL-X the cursor will be after the ruler. */
7374 setcursor();
7375#endif
7376
7377 /*
7378 * Don't map the second key. This also prevents the mode message to be
7379 * deleted when ESC is hit.
7380 */
7381 ++no_mapping;
7382 c = safe_vgetc();
7383 --no_mapping;
7384 switch (c)
7385 {
7386 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
7387 case K_UP:
7388 case Ctrl_K:
7389 case 'k': ins_up(TRUE);
7390 break;
7391
7392 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
7393 case K_DOWN:
7394 case Ctrl_J:
7395 case 'j': ins_down(TRUE);
7396 break;
7397
7398 /* CTRL-G u: start new undoable edit */
Bram Moolenaar779b74b2006-04-10 14:55:34 +00007399 case 'u': u_sync(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007400 ins_need_undo = TRUE;
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00007401
7402 /* Need to reset Insstart, esp. because a BS that joins
7403 * aline to the previous one must save for undo. */
7404 Insstart = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007405 break;
7406
7407 /* Unknown CTRL-G command, reserved for future expansion. */
7408 default: vim_beep();
7409 }
7410}
7411
7412/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007413 * CTRL-^ in Insert mode.
7414 */
7415 static void
7416ins_ctrl_hat()
7417{
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00007418 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007419 {
7420 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
7421 if (State & LANGMAP)
7422 {
7423 curbuf->b_p_iminsert = B_IMODE_NONE;
7424 State &= ~LANGMAP;
7425 }
7426 else
7427 {
7428 curbuf->b_p_iminsert = B_IMODE_LMAP;
7429 State |= LANGMAP;
7430#ifdef USE_IM_CONTROL
7431 im_set_active(FALSE);
7432#endif
7433 }
7434 }
7435#ifdef USE_IM_CONTROL
7436 else
7437 {
7438 /* There are no ":lmap" mappings, toggle IM */
7439 if (im_get_status())
7440 {
7441 curbuf->b_p_iminsert = B_IMODE_NONE;
7442 im_set_active(FALSE);
7443 }
7444 else
7445 {
7446 curbuf->b_p_iminsert = B_IMODE_IM;
7447 State &= ~LANGMAP;
7448 im_set_active(TRUE);
7449 }
7450 }
7451#endif
7452 set_iminsert_global();
7453 showmode();
7454#ifdef FEAT_GUI
7455 /* may show different cursor shape or color */
7456 if (gui.in_use)
7457 gui_update_cursor(TRUE, FALSE);
7458#endif
7459#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
7460 /* Show/unshow value of 'keymap' in status lines. */
7461 status_redraw_curbuf();
7462#endif
7463}
7464
7465/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007466 * Handle ESC in insert mode.
7467 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
7468 * insert.
7469 */
7470 static int
Bram Moolenaar488c6512005-08-11 20:09:58 +00007471ins_esc(count, cmdchar, nomove)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007472 long *count;
7473 int cmdchar;
Bram Moolenaar488c6512005-08-11 20:09:58 +00007474 int nomove; /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007475{
7476 int temp;
7477 static int disabled_redraw = FALSE;
7478
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00007479#ifdef FEAT_SPELL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007480 check_spell_redraw();
7481#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007482#if defined(FEAT_HANGULIN)
7483# if defined(ESC_CHG_TO_ENG_MODE)
7484 hangul_input_state_set(0);
7485# endif
7486 if (composing_hangul)
7487 {
7488 push_raw_key(composing_hangul_buffer, 2);
7489 composing_hangul = 0;
7490 }
7491#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007492
7493 temp = curwin->w_cursor.col;
7494 if (disabled_redraw)
7495 {
7496 --RedrawingDisabled;
7497 disabled_redraw = FALSE;
7498 }
7499 if (!arrow_used)
7500 {
7501 /*
7502 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00007503 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
7504 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007505 */
7506 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00007507 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007508
7509 /*
7510 * Repeating insert may take a long time. Check for
7511 * interrupt now and then.
7512 */
7513 if (*count > 0)
7514 {
7515 line_breakcheck();
7516 if (got_int)
7517 *count = 0;
7518 }
7519
7520 if (--*count > 0) /* repeat what was typed */
7521 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00007522 /* Vi repeats the insert without replacing characters. */
7523 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
7524 State &= ~REPLACE_FLAG;
7525
Bram Moolenaar071d4272004-06-13 20:20:40 +00007526 (void)start_redo_ins();
7527 if (cmdchar == 'r' || cmdchar == 'v')
7528 stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
7529 ++RedrawingDisabled;
7530 disabled_redraw = TRUE;
7531 return FALSE; /* repeat the insert */
7532 }
7533 stop_insert(&curwin->w_cursor, TRUE);
7534 undisplay_dollar();
7535 }
7536
7537 /* When an autoindent was removed, curswant stays after the
7538 * indent */
7539 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
7540 curwin->w_set_curswant = TRUE;
7541
7542 /* Remember the last Insert position in the '^ mark. */
7543 if (!cmdmod.keepjumps)
7544 curbuf->b_last_insert = curwin->w_cursor;
7545
7546 /*
7547 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00007548 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007549 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00007550 if (!nomove
7551 && (curwin->w_cursor.col != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007552#ifdef FEAT_VIRTUALEDIT
7553 || curwin->w_cursor.coladd > 0
7554#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007555 )
7556 && (restart_edit == NUL
7557 || (gchar_cursor() == NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007558#ifdef FEAT_VISUAL
Bram Moolenaar488c6512005-08-11 20:09:58 +00007559 && !VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +00007560#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007561 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007562#ifdef FEAT_RIGHTLEFT
7563 && !revins_on
7564#endif
7565 )
7566 {
7567#ifdef FEAT_VIRTUALEDIT
7568 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
7569 {
7570 oneleft();
7571 if (restart_edit != NUL)
7572 ++curwin->w_cursor.coladd;
7573 }
7574 else
7575#endif
7576 {
7577 --curwin->w_cursor.col;
7578#ifdef FEAT_MBYTE
7579 /* Correct cursor for multi-byte character. */
7580 if (has_mbyte)
7581 mb_adjust_cursor();
7582#endif
7583 }
7584 }
7585
7586#ifdef USE_IM_CONTROL
7587 /* Disable IM to allow typing English directly for Normal mode commands.
7588 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
7589 * well). */
7590 if (!(State & LANGMAP))
7591 im_save_status(&curbuf->b_p_iminsert);
7592 im_set_active(FALSE);
7593#endif
7594
7595 State = NORMAL;
7596 /* need to position cursor again (e.g. when on a TAB ) */
7597 changed_cline_bef_curs();
7598
7599#ifdef FEAT_MOUSE
7600 setmouse();
7601#endif
7602#ifdef CURSOR_SHAPE
7603 ui_cursor_shape(); /* may show different cursor shape */
7604#endif
7605
7606 /*
7607 * When recording or for CTRL-O, need to display the new mode.
7608 * Otherwise remove the mode message.
7609 */
7610 if (Recording || restart_edit != NUL)
7611 showmode();
7612 else if (p_smd)
7613 MSG("");
7614
7615 return TRUE; /* exit Insert mode */
7616}
7617
7618#ifdef FEAT_RIGHTLEFT
7619/*
7620 * Toggle language: hkmap and revins_on.
7621 * Move to end of reverse inserted text.
7622 */
7623 static void
7624ins_ctrl_()
7625{
7626 if (revins_on && revins_chars && revins_scol >= 0)
7627 {
7628 while (gchar_cursor() != NUL && revins_chars--)
7629 ++curwin->w_cursor.col;
7630 }
7631 p_ri = !p_ri;
7632 revins_on = (State == INSERT && p_ri);
7633 if (revins_on)
7634 {
7635 revins_scol = curwin->w_cursor.col;
7636 revins_legal++;
7637 revins_chars = 0;
7638 undisplay_dollar();
7639 }
7640 else
7641 revins_scol = -1;
7642#ifdef FEAT_FKMAP
7643 if (p_altkeymap)
7644 {
7645 /*
7646 * to be consistent also for redo command, using '.'
7647 * set arrow_used to true and stop it - causing to redo
7648 * characters entered in one mode (normal/reverse insert).
7649 */
7650 arrow_used = TRUE;
7651 (void)stop_arrow();
7652 p_fkmap = curwin->w_p_rl ^ p_ri;
7653 if (p_fkmap && p_ri)
7654 State = INSERT;
7655 }
7656 else
7657#endif
7658 p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
7659 showmode();
7660}
7661#endif
7662
7663#ifdef FEAT_VISUAL
7664/*
7665 * If 'keymodel' contains "startsel", may start selection.
7666 * Returns TRUE when a CTRL-O and other keys stuffed.
7667 */
7668 static int
7669ins_start_select(c)
7670 int c;
7671{
7672 if (km_startsel)
7673 switch (c)
7674 {
7675 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007676 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007677 case K_PAGEUP:
7678 case K_KPAGEUP:
7679 case K_PAGEDOWN:
7680 case K_KPAGEDOWN:
7681# ifdef MACOS
7682 case K_LEFT:
7683 case K_RIGHT:
7684 case K_UP:
7685 case K_DOWN:
7686 case K_END:
7687 case K_HOME:
7688# endif
7689 if (!(mod_mask & MOD_MASK_SHIFT))
7690 break;
7691 /* FALLTHROUGH */
7692 case K_S_LEFT:
7693 case K_S_RIGHT:
7694 case K_S_UP:
7695 case K_S_DOWN:
7696 case K_S_END:
7697 case K_S_HOME:
7698 /* Start selection right away, the cursor can move with
7699 * CTRL-O when beyond the end of the line. */
7700 start_selection();
7701
7702 /* Execute the key in (insert) Select mode. */
7703 stuffcharReadbuff(Ctrl_O);
7704 if (mod_mask)
7705 {
7706 char_u buf[4];
7707
7708 buf[0] = K_SPECIAL;
7709 buf[1] = KS_MODIFIER;
7710 buf[2] = mod_mask;
7711 buf[3] = NUL;
7712 stuffReadbuff(buf);
7713 }
7714 stuffcharReadbuff(c);
7715 return TRUE;
7716 }
7717 return FALSE;
7718}
7719#endif
7720
7721/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007722 * <Insert> key in Insert mode: toggle insert/remplace mode.
7723 */
7724 static void
7725ins_insert(replaceState)
7726 int replaceState;
7727{
7728#ifdef FEAT_FKMAP
7729 if (p_fkmap && p_ri)
7730 {
7731 beep_flush();
7732 EMSG(farsi_text_3); /* encoded in Farsi */
7733 return;
7734 }
7735#endif
7736
7737#ifdef FEAT_AUTOCMD
Bram Moolenaar1e015462005-09-25 22:16:38 +00007738# ifdef FEAT_EVAL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007739 set_vim_var_string(VV_INSERTMODE,
7740 (char_u *)((State & REPLACE_FLAG) ? "i" :
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00007741# ifdef FEAT_VREPLACE
7742 replaceState == VREPLACE ? "v" :
7743# endif
7744 "r"), 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00007745# endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007746 apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
7747#endif
7748 if (State & REPLACE_FLAG)
7749 State = INSERT | (State & LANGMAP);
7750 else
7751 State = replaceState | (State & LANGMAP);
7752 AppendCharToRedobuff(K_INS);
7753 showmode();
7754#ifdef CURSOR_SHAPE
7755 ui_cursor_shape(); /* may show different cursor shape */
7756#endif
7757}
7758
7759/*
7760 * Pressed CTRL-O in Insert mode.
7761 */
7762 static void
7763ins_ctrl_o()
7764{
7765#ifdef FEAT_VREPLACE
7766 if (State & VREPLACE_FLAG)
7767 restart_edit = 'V';
7768 else
7769#endif
7770 if (State & REPLACE_FLAG)
7771 restart_edit = 'R';
7772 else
7773 restart_edit = 'I';
7774#ifdef FEAT_VIRTUALEDIT
7775 if (virtual_active())
7776 ins_at_eol = FALSE; /* cursor always keeps its column */
7777 else
7778#endif
7779 ins_at_eol = (gchar_cursor() == NUL);
7780}
7781
7782/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007783 * If the cursor is on an indent, ^T/^D insert/delete one
7784 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
7785 * Always round the indent to 'shiftwith', this is compatible
7786 * with vi. But vi only supports ^T and ^D after an
7787 * autoindent, we support it everywhere.
7788 */
7789 static void
7790ins_shift(c, lastc)
7791 int c;
7792 int lastc;
7793{
7794 if (stop_arrow() == FAIL)
7795 return;
7796 AppendCharToRedobuff(c);
7797
7798 /*
7799 * 0^D and ^^D: remove all indent.
7800 */
7801 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
7802 {
7803 --curwin->w_cursor.col;
7804 (void)del_char(FALSE); /* delete the '^' or '0' */
7805 /* In Replace mode, restore the characters that '^' or '0' replaced. */
7806 if (State & REPLACE_FLAG)
7807 replace_pop_ins();
7808 if (lastc == '^')
7809 old_indent = get_indent(); /* remember curr. indent */
7810 change_indent(INDENT_SET, 0, TRUE, 0);
7811 }
7812 else
7813 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
7814
7815 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
7816 did_ai = FALSE;
7817#ifdef FEAT_SMARTINDENT
7818 did_si = FALSE;
7819 can_si = FALSE;
7820 can_si_back = FALSE;
7821#endif
7822#ifdef FEAT_CINDENT
7823 can_cindent = FALSE; /* no cindenting after ^D or ^T */
7824#endif
7825}
7826
7827 static void
7828ins_del()
7829{
7830 int temp;
7831
7832 if (stop_arrow() == FAIL)
7833 return;
7834 if (gchar_cursor() == NUL) /* delete newline */
7835 {
7836 temp = curwin->w_cursor.col;
7837 if (!can_bs(BS_EOL) /* only if "eol" included */
7838 || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
7839 (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
7840 || do_join(FALSE) == FAIL)
7841 vim_beep();
7842 else
7843 curwin->w_cursor.col = temp;
7844 }
7845 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
7846 vim_beep();
7847 did_ai = FALSE;
7848#ifdef FEAT_SMARTINDENT
7849 did_si = FALSE;
7850 can_si = FALSE;
7851 can_si_back = FALSE;
7852#endif
7853 AppendCharToRedobuff(K_DEL);
7854}
7855
7856/*
7857 * Handle Backspace, delete-word and delete-line in Insert mode.
7858 * Return TRUE when backspace was actually used.
7859 */
7860 static int
7861ins_bs(c, mode, inserted_space_p)
7862 int c;
7863 int mode;
7864 int *inserted_space_p;
7865{
7866 linenr_T lnum;
7867 int cc;
7868 int temp = 0; /* init for GCC */
7869 colnr_T mincol;
7870 int did_backspace = FALSE;
7871 int in_indent;
7872 int oldState;
7873#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007874 int cpc[MAX_MCO]; /* composing characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007875#endif
7876
7877 /*
7878 * can't delete anything in an empty file
7879 * can't backup past first character in buffer
7880 * can't backup past starting point unless 'backspace' > 1
7881 * can backup to a previous line if 'backspace' == 0
7882 */
7883 if ( bufempty()
7884 || (
7885#ifdef FEAT_RIGHTLEFT
7886 !revins_on &&
7887#endif
7888 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
7889 || (!can_bs(BS_START)
7890 && (arrow_used
7891 || (curwin->w_cursor.lnum == Insstart.lnum
7892 && curwin->w_cursor.col <= Insstart.col)))
7893 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
7894 && curwin->w_cursor.col <= ai_col)
7895 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
7896 {
7897 vim_beep();
7898 return FALSE;
7899 }
7900
7901 if (stop_arrow() == FAIL)
7902 return FALSE;
7903 in_indent = inindent(0);
7904#ifdef FEAT_CINDENT
7905 if (in_indent)
7906 can_cindent = FALSE;
7907#endif
7908#ifdef FEAT_COMMENTS
7909 end_comment_pending = NUL; /* After BS, don't auto-end comment */
7910#endif
7911#ifdef FEAT_RIGHTLEFT
7912 if (revins_on) /* put cursor after last inserted char */
7913 inc_cursor();
7914#endif
7915
7916#ifdef FEAT_VIRTUALEDIT
7917 /* Virtualedit:
7918 * BACKSPACE_CHAR eats a virtual space
7919 * BACKSPACE_WORD eats all coladd
7920 * BACKSPACE_LINE eats all coladd and keeps going
7921 */
7922 if (curwin->w_cursor.coladd > 0)
7923 {
7924 if (mode == BACKSPACE_CHAR)
7925 {
7926 --curwin->w_cursor.coladd;
7927 return TRUE;
7928 }
7929 if (mode == BACKSPACE_WORD)
7930 {
7931 curwin->w_cursor.coladd = 0;
7932 return TRUE;
7933 }
7934 curwin->w_cursor.coladd = 0;
7935 }
7936#endif
7937
7938 /*
7939 * delete newline!
7940 */
7941 if (curwin->w_cursor.col == 0)
7942 {
7943 lnum = Insstart.lnum;
7944 if (curwin->w_cursor.lnum == Insstart.lnum
7945#ifdef FEAT_RIGHTLEFT
7946 || revins_on
7947#endif
7948 )
7949 {
7950 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
7951 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
7952 return FALSE;
7953 --Insstart.lnum;
7954 Insstart.col = MAXCOL;
7955 }
7956 /*
7957 * In replace mode:
7958 * cc < 0: NL was inserted, delete it
7959 * cc >= 0: NL was replaced, put original characters back
7960 */
7961 cc = -1;
7962 if (State & REPLACE_FLAG)
7963 cc = replace_pop(); /* returns -1 if NL was inserted */
7964 /*
7965 * In replace mode, in the line we started replacing, we only move the
7966 * cursor.
7967 */
7968 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
7969 {
7970 dec_cursor();
7971 }
7972 else
7973 {
7974#ifdef FEAT_VREPLACE
7975 if (!(State & VREPLACE_FLAG)
7976 || curwin->w_cursor.lnum > orig_line_count)
7977#endif
7978 {
7979 temp = gchar_cursor(); /* remember current char */
7980 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00007981
7982 /* When "aw" is in 'formatoptions' we must delete the space at
7983 * the end of the line, otherwise the line will be broken
7984 * again when auto-formatting. */
7985 if (has_format_option(FO_AUTO)
7986 && has_format_option(FO_WHITE_PAR))
7987 {
7988 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
7989 TRUE);
7990 int len;
7991
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00007992 len = (int)STRLEN(ptr);
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00007993 if (len > 0 && ptr[len - 1] == ' ')
7994 ptr[len - 1] = NUL;
7995 }
7996
Bram Moolenaar071d4272004-06-13 20:20:40 +00007997 (void)do_join(FALSE);
7998 if (temp == NUL && gchar_cursor() != NUL)
7999 inc_cursor();
8000 }
8001#ifdef FEAT_VREPLACE
8002 else
8003 dec_cursor();
8004#endif
8005
8006 /*
8007 * In REPLACE mode we have to put back the text that was replaced
8008 * by the NL. On the replace stack is first a NUL-terminated
8009 * sequence of characters that were deleted and then the
8010 * characters that NL replaced.
8011 */
8012 if (State & REPLACE_FLAG)
8013 {
8014 /*
8015 * Do the next ins_char() in NORMAL state, to
8016 * prevent ins_char() from replacing characters and
8017 * avoiding showmatch().
8018 */
8019 oldState = State;
8020 State = NORMAL;
8021 /*
8022 * restore characters (blanks) deleted after cursor
8023 */
8024 while (cc > 0)
8025 {
8026 temp = curwin->w_cursor.col;
8027#ifdef FEAT_MBYTE
8028 mb_replace_pop_ins(cc);
8029#else
8030 ins_char(cc);
8031#endif
8032 curwin->w_cursor.col = temp;
8033 cc = replace_pop();
8034 }
8035 /* restore the characters that NL replaced */
8036 replace_pop_ins();
8037 State = oldState;
8038 }
8039 }
8040 did_ai = FALSE;
8041 }
8042 else
8043 {
8044 /*
8045 * Delete character(s) before the cursor.
8046 */
8047#ifdef FEAT_RIGHTLEFT
8048 if (revins_on) /* put cursor on last inserted char */
8049 dec_cursor();
8050#endif
8051 mincol = 0;
8052 /* keep indent */
8053 if (mode == BACKSPACE_LINE && curbuf->b_p_ai
8054#ifdef FEAT_RIGHTLEFT
8055 && !revins_on
8056#endif
8057 )
8058 {
8059 temp = curwin->w_cursor.col;
8060 beginline(BL_WHITE);
8061 if (curwin->w_cursor.col < (colnr_T)temp)
8062 mincol = curwin->w_cursor.col;
8063 curwin->w_cursor.col = temp;
8064 }
8065
8066 /*
8067 * Handle deleting one 'shiftwidth' or 'softtabstop'.
8068 */
8069 if ( mode == BACKSPACE_CHAR
8070 && ((p_sta && in_indent)
Bram Moolenaar280f1262006-01-30 00:14:18 +00008071 || (curbuf->b_p_sts != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008072 && (*(ml_get_cursor() - 1) == TAB
8073 || (*(ml_get_cursor() - 1) == ' '
8074 && (!*inserted_space_p
8075 || arrow_used))))))
8076 {
8077 int ts;
8078 colnr_T vcol;
8079 colnr_T want_vcol;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008080#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008081 int extra = 0;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008082#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008083
8084 *inserted_space_p = FALSE;
Bram Moolenaar280f1262006-01-30 00:14:18 +00008085 if (p_sta && in_indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008086 ts = curbuf->b_p_sw;
8087 else
8088 ts = curbuf->b_p_sts;
8089 /* Compute the virtual column where we want to be. Since
8090 * 'showbreak' may get in the way, need to get the last column of
8091 * the previous character. */
8092 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8093 dec_cursor();
8094 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
8095 inc_cursor();
8096 want_vcol = (want_vcol / ts) * ts;
8097
8098 /* delete characters until we are at or before want_vcol */
8099 while (vcol > want_vcol
8100 && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
8101 {
8102 dec_cursor();
8103 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8104 if (State & REPLACE_FLAG)
8105 {
8106 /* Don't delete characters before the insert point when in
8107 * Replace mode */
8108 if (curwin->w_cursor.lnum != Insstart.lnum
8109 || curwin->w_cursor.col >= Insstart.col)
8110 {
8111#if 0 /* what was this for? It causes problems when sw != ts. */
8112 if (State == REPLACE && (int)vcol < want_vcol)
8113 {
8114 (void)del_char(FALSE);
8115 extra = 2; /* don't pop too much */
8116 }
8117 else
8118#endif
8119 replace_do_bs();
8120 }
8121 }
8122 else
8123 (void)del_char(FALSE);
8124 }
8125
8126 /* insert extra spaces until we are at want_vcol */
8127 while (vcol < want_vcol)
8128 {
8129 /* Remember the first char we inserted */
8130 if (curwin->w_cursor.lnum == Insstart.lnum
8131 && curwin->w_cursor.col < Insstart.col)
8132 Insstart.col = curwin->w_cursor.col;
8133
8134#ifdef FEAT_VREPLACE
8135 if (State & VREPLACE_FLAG)
8136 ins_char(' ');
8137 else
8138#endif
8139 {
8140 ins_str((char_u *)" ");
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008141 if ((State & REPLACE_FLAG) /* && extra <= 1 */)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008142 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008143#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008144 if (extra)
8145 replace_push_off(NUL);
8146 else
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008147#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008148 replace_push(NUL);
8149 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008150#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008151 if (extra == 2)
8152 extra = 1;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008153#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008154 }
8155 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8156 }
8157 }
8158
8159 /*
8160 * Delete upto starting point, start of line or previous word.
8161 */
8162 else do
8163 {
8164#ifdef FEAT_RIGHTLEFT
8165 if (!revins_on) /* put cursor on char to be deleted */
8166#endif
8167 dec_cursor();
8168
8169 /* start of word? */
8170 if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
8171 {
8172 mode = BACKSPACE_WORD_NOT_SPACE;
8173 temp = vim_iswordc(gchar_cursor());
8174 }
8175 /* end of word? */
8176 else if (mode == BACKSPACE_WORD_NOT_SPACE
8177 && (vim_isspace(cc = gchar_cursor())
8178 || vim_iswordc(cc) != temp))
8179 {
8180#ifdef FEAT_RIGHTLEFT
8181 if (!revins_on)
8182#endif
8183 inc_cursor();
8184#ifdef FEAT_RIGHTLEFT
8185 else if (State & REPLACE_FLAG)
8186 dec_cursor();
8187#endif
8188 break;
8189 }
8190 if (State & REPLACE_FLAG)
8191 replace_do_bs();
8192 else
8193 {
8194#ifdef FEAT_MBYTE
8195 if (enc_utf8 && p_deco)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008196 (void)utfc_ptr2char(ml_get_cursor(), cpc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008197#endif
8198 (void)del_char(FALSE);
8199#ifdef FEAT_MBYTE
8200 /*
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008201 * If there are combining characters and 'delcombine' is set
8202 * move the cursor back. Don't back up before the base
Bram Moolenaar071d4272004-06-13 20:20:40 +00008203 * character.
8204 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008205 if (enc_utf8 && p_deco && cpc[0] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008206 inc_cursor();
8207#endif
8208#ifdef FEAT_RIGHTLEFT
8209 if (revins_chars)
8210 {
8211 revins_chars--;
8212 revins_legal++;
8213 }
8214 if (revins_on && gchar_cursor() == NUL)
8215 break;
8216#endif
8217 }
8218 /* Just a single backspace?: */
8219 if (mode == BACKSPACE_CHAR)
8220 break;
8221 } while (
8222#ifdef FEAT_RIGHTLEFT
8223 revins_on ||
8224#endif
8225 (curwin->w_cursor.col > mincol
8226 && (curwin->w_cursor.lnum != Insstart.lnum
8227 || curwin->w_cursor.col != Insstart.col)));
8228 did_backspace = TRUE;
8229 }
8230#ifdef FEAT_SMARTINDENT
8231 did_si = FALSE;
8232 can_si = FALSE;
8233 can_si_back = FALSE;
8234#endif
8235 if (curwin->w_cursor.col <= 1)
8236 did_ai = FALSE;
8237 /*
8238 * It's a little strange to put backspaces into the redo
8239 * buffer, but it makes auto-indent a lot easier to deal
8240 * with.
8241 */
8242 AppendCharToRedobuff(c);
8243
8244 /* If deleted before the insertion point, adjust it */
8245 if (curwin->w_cursor.lnum == Insstart.lnum
8246 && curwin->w_cursor.col < Insstart.col)
8247 Insstart.col = curwin->w_cursor.col;
8248
8249 /* vi behaviour: the cursor moves backward but the character that
8250 * was there remains visible
8251 * Vim behaviour: the cursor moves backward and the character that
8252 * was there is erased from the screen.
8253 * We can emulate the vi behaviour by pretending there is a dollar
8254 * displayed even when there isn't.
8255 * --pkv Sun Jan 19 01:56:40 EST 2003 */
8256 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == 0)
8257 dollar_vcol = curwin->w_virtcol;
8258
8259 return did_backspace;
8260}
8261
8262#ifdef FEAT_MOUSE
8263 static void
8264ins_mouse(c)
8265 int c;
8266{
8267 pos_T tpos;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008268 win_T *old_curwin = curwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008269
8270# ifdef FEAT_GUI
8271 /* When GUI is active, also move/paste when 'mouse' is empty */
8272 if (!gui.in_use)
8273# endif
8274 if (!mouse_has(MOUSE_INSERT))
8275 return;
8276
8277 undisplay_dollar();
8278 tpos = curwin->w_cursor;
8279 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
8280 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008281#ifdef FEAT_WINDOWS
8282 win_T *new_curwin = curwin;
8283
8284 if (curwin != old_curwin && win_valid(old_curwin))
8285 {
8286 /* Mouse took us to another window. We need to go back to the
8287 * previous one to stop insert there properly. */
8288 curwin = old_curwin;
8289 curbuf = curwin->w_buffer;
8290 }
8291#endif
8292 start_arrow(curwin == old_curwin ? &tpos : NULL);
8293#ifdef FEAT_WINDOWS
8294 if (curwin != new_curwin && win_valid(new_curwin))
8295 {
8296 curwin = new_curwin;
8297 curbuf = curwin->w_buffer;
8298 }
8299#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008300# ifdef FEAT_CINDENT
8301 can_cindent = TRUE;
8302# endif
8303 }
8304
8305#ifdef FEAT_WINDOWS
8306 /* redraw status lines (in case another window became active) */
8307 redraw_statuslines();
8308#endif
8309}
8310
8311 static void
8312ins_mousescroll(up)
8313 int up;
8314{
8315 pos_T tpos;
8316# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8317 win_T *old_curwin;
8318# endif
8319
8320 tpos = curwin->w_cursor;
8321
8322# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8323 old_curwin = curwin;
8324
8325 /* Currently the mouse coordinates are only known in the GUI. */
8326 if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
8327 {
8328 int row, col;
8329
8330 row = mouse_row;
8331 col = mouse_col;
8332
8333 /* find the window at the pointer coordinates */
8334 curwin = mouse_find_win(&row, &col);
8335 curbuf = curwin->w_buffer;
8336 }
8337 if (curwin == old_curwin)
8338# endif
8339 undisplay_dollar();
8340
8341 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
8342 scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
8343 else
8344 scroll_redraw(up, 3L);
8345
8346# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8347 curwin->w_redr_status = TRUE;
8348
8349 curwin = old_curwin;
8350 curbuf = curwin->w_buffer;
8351# endif
8352
8353 if (!equalpos(curwin->w_cursor, tpos))
8354 {
8355 start_arrow(&tpos);
8356# ifdef FEAT_CINDENT
8357 can_cindent = TRUE;
8358# endif
8359 }
8360}
8361#endif
8362
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008363#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00008364 static void
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008365ins_tabline(c)
8366 int c;
8367{
8368 /* We will be leaving the current window, unless closing another tab. */
8369 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE
8370 || (current_tab != 0 && current_tab != tabpage_index(curtab)))
8371 {
8372 undisplay_dollar();
8373 start_arrow(&curwin->w_cursor);
8374# ifdef FEAT_CINDENT
8375 can_cindent = TRUE;
8376# endif
8377 }
8378
8379 if (c == K_TABLINE)
8380 goto_tabpage(current_tab);
8381 else
8382 handle_tabmenu();
8383
8384}
8385#endif
8386
8387#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008388 void
8389ins_scroll()
8390{
8391 pos_T tpos;
8392
8393 undisplay_dollar();
8394 tpos = curwin->w_cursor;
8395 if (gui_do_scroll())
8396 {
8397 start_arrow(&tpos);
8398# ifdef FEAT_CINDENT
8399 can_cindent = TRUE;
8400# endif
8401 }
8402}
8403
8404 void
8405ins_horscroll()
8406{
8407 pos_T tpos;
8408
8409 undisplay_dollar();
8410 tpos = curwin->w_cursor;
8411 if (gui_do_horiz_scroll())
8412 {
8413 start_arrow(&tpos);
8414# ifdef FEAT_CINDENT
8415 can_cindent = TRUE;
8416# endif
8417 }
8418}
8419#endif
8420
8421 static void
8422ins_left()
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 (oneleft() == OK)
8433 {
8434 start_arrow(&tpos);
8435#ifdef FEAT_RIGHTLEFT
8436 /* If exit reversed string, position is fixed */
8437 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
8438 revins_legal++;
8439 revins_chars++;
8440#endif
8441 }
8442
8443 /*
8444 * if 'whichwrap' set for cursor in insert mode may go to
8445 * previous line
8446 */
8447 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
8448 {
8449 start_arrow(&tpos);
8450 --(curwin->w_cursor.lnum);
8451 coladvance((colnr_T)MAXCOL);
8452 curwin->w_set_curswant = TRUE; /* so we stay at the end */
8453 }
8454 else
8455 vim_beep();
8456}
8457
8458 static void
8459ins_home(c)
8460 int c;
8461{
8462 pos_T tpos;
8463
8464#ifdef FEAT_FOLDING
8465 if ((fdo_flags & FDO_HOR) && KeyTyped)
8466 foldOpenCursor();
8467#endif
8468 undisplay_dollar();
8469 tpos = curwin->w_cursor;
8470 if (c == K_C_HOME)
8471 curwin->w_cursor.lnum = 1;
8472 curwin->w_cursor.col = 0;
8473#ifdef FEAT_VIRTUALEDIT
8474 curwin->w_cursor.coladd = 0;
8475#endif
8476 curwin->w_curswant = 0;
8477 start_arrow(&tpos);
8478}
8479
8480 static void
8481ins_end(c)
8482 int c;
8483{
8484 pos_T tpos;
8485
8486#ifdef FEAT_FOLDING
8487 if ((fdo_flags & FDO_HOR) && KeyTyped)
8488 foldOpenCursor();
8489#endif
8490 undisplay_dollar();
8491 tpos = curwin->w_cursor;
8492 if (c == K_C_END)
8493 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
8494 coladvance((colnr_T)MAXCOL);
8495 curwin->w_curswant = MAXCOL;
8496
8497 start_arrow(&tpos);
8498}
8499
8500 static void
8501ins_s_left()
8502{
8503#ifdef FEAT_FOLDING
8504 if ((fdo_flags & FDO_HOR) && KeyTyped)
8505 foldOpenCursor();
8506#endif
8507 undisplay_dollar();
8508 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
8509 {
8510 start_arrow(&curwin->w_cursor);
8511 (void)bck_word(1L, FALSE, FALSE);
8512 curwin->w_set_curswant = TRUE;
8513 }
8514 else
8515 vim_beep();
8516}
8517
8518 static void
8519ins_right()
8520{
8521#ifdef FEAT_FOLDING
8522 if ((fdo_flags & FDO_HOR) && KeyTyped)
8523 foldOpenCursor();
8524#endif
8525 undisplay_dollar();
8526 if (gchar_cursor() != NUL || virtual_active()
8527 )
8528 {
8529 start_arrow(&curwin->w_cursor);
8530 curwin->w_set_curswant = TRUE;
8531#ifdef FEAT_VIRTUALEDIT
8532 if (virtual_active())
8533 oneright();
8534 else
8535#endif
8536 {
8537#ifdef FEAT_MBYTE
8538 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00008539 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00008540 else
8541#endif
8542 ++curwin->w_cursor.col;
8543 }
8544
8545#ifdef FEAT_RIGHTLEFT
8546 revins_legal++;
8547 if (revins_chars)
8548 revins_chars--;
8549#endif
8550 }
8551 /* if 'whichwrap' set for cursor in insert mode, may move the
8552 * cursor to the next line */
8553 else if (vim_strchr(p_ww, ']') != NULL
8554 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
8555 {
8556 start_arrow(&curwin->w_cursor);
8557 curwin->w_set_curswant = TRUE;
8558 ++curwin->w_cursor.lnum;
8559 curwin->w_cursor.col = 0;
8560 }
8561 else
8562 vim_beep();
8563}
8564
8565 static void
8566ins_s_right()
8567{
8568#ifdef FEAT_FOLDING
8569 if ((fdo_flags & FDO_HOR) && KeyTyped)
8570 foldOpenCursor();
8571#endif
8572 undisplay_dollar();
8573 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
8574 || gchar_cursor() != NUL)
8575 {
8576 start_arrow(&curwin->w_cursor);
8577 (void)fwd_word(1L, FALSE, 0);
8578 curwin->w_set_curswant = TRUE;
8579 }
8580 else
8581 vim_beep();
8582}
8583
8584 static void
8585ins_up(startcol)
8586 int startcol; /* when TRUE move to Insstart.col */
8587{
8588 pos_T tpos;
8589 linenr_T old_topline = curwin->w_topline;
8590#ifdef FEAT_DIFF
8591 int old_topfill = curwin->w_topfill;
8592#endif
8593
8594 undisplay_dollar();
8595 tpos = curwin->w_cursor;
8596 if (cursor_up(1L, TRUE) == OK)
8597 {
8598 if (startcol)
8599 coladvance(getvcol_nolist(&Insstart));
8600 if (old_topline != curwin->w_topline
8601#ifdef FEAT_DIFF
8602 || old_topfill != curwin->w_topfill
8603#endif
8604 )
8605 redraw_later(VALID);
8606 start_arrow(&tpos);
8607#ifdef FEAT_CINDENT
8608 can_cindent = TRUE;
8609#endif
8610 }
8611 else
8612 vim_beep();
8613}
8614
8615 static void
8616ins_pageup()
8617{
8618 pos_T tpos;
8619
8620 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008621
8622#ifdef FEAT_WINDOWS
8623 if (mod_mask & MOD_MASK_CTRL)
8624 {
8625 /* <C-PageUp>: tab page back */
8626 goto_tabpage(-1);
8627 return;
8628 }
8629#endif
8630
Bram Moolenaar071d4272004-06-13 20:20:40 +00008631 tpos = curwin->w_cursor;
8632 if (onepage(BACKWARD, 1L) == OK)
8633 {
8634 start_arrow(&tpos);
8635#ifdef FEAT_CINDENT
8636 can_cindent = TRUE;
8637#endif
8638 }
8639 else
8640 vim_beep();
8641}
8642
8643 static void
8644ins_down(startcol)
8645 int startcol; /* when TRUE move to Insstart.col */
8646{
8647 pos_T tpos;
8648 linenr_T old_topline = curwin->w_topline;
8649#ifdef FEAT_DIFF
8650 int old_topfill = curwin->w_topfill;
8651#endif
8652
8653 undisplay_dollar();
8654 tpos = curwin->w_cursor;
8655 if (cursor_down(1L, TRUE) == OK)
8656 {
8657 if (startcol)
8658 coladvance(getvcol_nolist(&Insstart));
8659 if (old_topline != curwin->w_topline
8660#ifdef FEAT_DIFF
8661 || old_topfill != curwin->w_topfill
8662#endif
8663 )
8664 redraw_later(VALID);
8665 start_arrow(&tpos);
8666#ifdef FEAT_CINDENT
8667 can_cindent = TRUE;
8668#endif
8669 }
8670 else
8671 vim_beep();
8672}
8673
8674 static void
8675ins_pagedown()
8676{
8677 pos_T tpos;
8678
8679 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008680
8681#ifdef FEAT_WINDOWS
8682 if (mod_mask & MOD_MASK_CTRL)
8683 {
8684 /* <C-PageDown>: tab page forward */
8685 goto_tabpage(0);
8686 return;
8687 }
8688#endif
8689
Bram Moolenaar071d4272004-06-13 20:20:40 +00008690 tpos = curwin->w_cursor;
8691 if (onepage(FORWARD, 1L) == OK)
8692 {
8693 start_arrow(&tpos);
8694#ifdef FEAT_CINDENT
8695 can_cindent = TRUE;
8696#endif
8697 }
8698 else
8699 vim_beep();
8700}
8701
8702#ifdef FEAT_DND
8703 static void
8704ins_drop()
8705{
8706 do_put('~', BACKWARD, 1L, PUT_CURSEND);
8707}
8708#endif
8709
8710/*
8711 * Handle TAB in Insert or Replace mode.
8712 * Return TRUE when the TAB needs to be inserted like a normal character.
8713 */
8714 static int
8715ins_tab()
8716{
8717 int ind;
8718 int i;
8719 int temp;
8720
8721 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
8722 Insstart_blank_vcol = get_nolist_virtcol();
8723 if (echeck_abbr(TAB + ABBR_OFF))
8724 return FALSE;
8725
8726 ind = inindent(0);
8727#ifdef FEAT_CINDENT
8728 if (ind)
8729 can_cindent = FALSE;
8730#endif
8731
8732 /*
8733 * When nothing special, insert TAB like a normal character
8734 */
8735 if (!curbuf->b_p_et
8736 && !(p_sta && ind && curbuf->b_p_ts != curbuf->b_p_sw)
8737 && curbuf->b_p_sts == 0)
8738 return TRUE;
8739
8740 if (stop_arrow() == FAIL)
8741 return TRUE;
8742
8743 did_ai = FALSE;
8744#ifdef FEAT_SMARTINDENT
8745 did_si = FALSE;
8746 can_si = FALSE;
8747 can_si_back = FALSE;
8748#endif
8749 AppendToRedobuff((char_u *)"\t");
8750
8751 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
8752 temp = (int)curbuf->b_p_sw;
8753 else if (curbuf->b_p_sts > 0) /* use 'softtabstop' when set */
8754 temp = (int)curbuf->b_p_sts;
8755 else /* otherwise use 'tabstop' */
8756 temp = (int)curbuf->b_p_ts;
8757 temp -= get_nolist_virtcol() % temp;
8758
8759 /*
8760 * Insert the first space with ins_char(). It will delete one char in
8761 * replace mode. Insert the rest with ins_str(); it will not delete any
8762 * chars. For VREPLACE mode, we use ins_char() for all characters.
8763 */
8764 ins_char(' ');
8765 while (--temp > 0)
8766 {
8767#ifdef FEAT_VREPLACE
8768 if (State & VREPLACE_FLAG)
8769 ins_char(' ');
8770 else
8771#endif
8772 {
8773 ins_str((char_u *)" ");
8774 if (State & REPLACE_FLAG) /* no char replaced */
8775 replace_push(NUL);
8776 }
8777 }
8778
8779 /*
8780 * When 'expandtab' not set: Replace spaces by TABs where possible.
8781 */
8782 if (!curbuf->b_p_et && (curbuf->b_p_sts || (p_sta && ind)))
8783 {
8784 char_u *ptr;
8785#ifdef FEAT_VREPLACE
8786 char_u *saved_line = NULL; /* init for GCC */
8787 pos_T pos;
8788#endif
8789 pos_T fpos;
8790 pos_T *cursor;
8791 colnr_T want_vcol, vcol;
8792 int change_col = -1;
8793 int save_list = curwin->w_p_list;
8794
8795 /*
8796 * Get the current line. For VREPLACE mode, don't make real changes
8797 * yet, just work on a copy of the line.
8798 */
8799#ifdef FEAT_VREPLACE
8800 if (State & VREPLACE_FLAG)
8801 {
8802 pos = curwin->w_cursor;
8803 cursor = &pos;
8804 saved_line = vim_strsave(ml_get_curline());
8805 if (saved_line == NULL)
8806 return FALSE;
8807 ptr = saved_line + pos.col;
8808 }
8809 else
8810#endif
8811 {
8812 ptr = ml_get_cursor();
8813 cursor = &curwin->w_cursor;
8814 }
8815
8816 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
8817 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8818 curwin->w_p_list = FALSE;
8819
8820 /* Find first white before the cursor */
8821 fpos = curwin->w_cursor;
8822 while (fpos.col > 0 && vim_iswhite(ptr[-1]))
8823 {
8824 --fpos.col;
8825 --ptr;
8826 }
8827
8828 /* In Replace mode, don't change characters before the insert point. */
8829 if ((State & REPLACE_FLAG)
8830 && fpos.lnum == Insstart.lnum
8831 && fpos.col < Insstart.col)
8832 {
8833 ptr += Insstart.col - fpos.col;
8834 fpos.col = Insstart.col;
8835 }
8836
8837 /* compute virtual column numbers of first white and cursor */
8838 getvcol(curwin, &fpos, &vcol, NULL, NULL);
8839 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
8840
8841 /* Use as many TABs as possible. Beware of 'showbreak' and
8842 * 'linebreak' adding extra virtual columns. */
8843 while (vim_iswhite(*ptr))
8844 {
8845 i = lbr_chartabsize((char_u *)"\t", vcol);
8846 if (vcol + i > want_vcol)
8847 break;
8848 if (*ptr != TAB)
8849 {
8850 *ptr = TAB;
8851 if (change_col < 0)
8852 {
8853 change_col = fpos.col; /* Column of first change */
8854 /* May have to adjust Insstart */
8855 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
8856 Insstart.col = fpos.col;
8857 }
8858 }
8859 ++fpos.col;
8860 ++ptr;
8861 vcol += i;
8862 }
8863
8864 if (change_col >= 0)
8865 {
8866 int repl_off = 0;
8867
8868 /* Skip over the spaces we need. */
8869 while (vcol < want_vcol && *ptr == ' ')
8870 {
8871 vcol += lbr_chartabsize(ptr, vcol);
8872 ++ptr;
8873 ++repl_off;
8874 }
8875 if (vcol > want_vcol)
8876 {
8877 /* Must have a char with 'showbreak' just before it. */
8878 --ptr;
8879 --repl_off;
8880 }
8881 fpos.col += repl_off;
8882
8883 /* Delete following spaces. */
8884 i = cursor->col - fpos.col;
8885 if (i > 0)
8886 {
8887 mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
8888 /* correct replace stack. */
8889 if ((State & REPLACE_FLAG)
8890#ifdef FEAT_VREPLACE
8891 && !(State & VREPLACE_FLAG)
8892#endif
8893 )
8894 for (temp = i; --temp >= 0; )
8895 replace_join(repl_off);
8896 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00008897#ifdef FEAT_NETBEANS_INTG
8898 if (usingNetbeans)
8899 {
8900 netbeans_removed(curbuf, fpos.lnum, cursor->col,
8901 (long)(i + 1));
8902 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
8903 (char_u *)"\t", 1);
8904 }
8905#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008906 cursor->col -= i;
8907
8908#ifdef FEAT_VREPLACE
8909 /*
8910 * In VREPLACE mode, we haven't changed anything yet. Do it now by
8911 * backspacing over the changed spacing and then inserting the new
8912 * spacing.
8913 */
8914 if (State & VREPLACE_FLAG)
8915 {
8916 /* Backspace from real cursor to change_col */
8917 backspace_until_column(change_col);
8918
8919 /* Insert each char in saved_line from changed_col to
8920 * ptr-cursor */
8921 ins_bytes_len(saved_line + change_col,
8922 cursor->col - change_col);
8923 }
8924#endif
8925 }
8926
8927#ifdef FEAT_VREPLACE
8928 if (State & VREPLACE_FLAG)
8929 vim_free(saved_line);
8930#endif
8931 curwin->w_p_list = save_list;
8932 }
8933
8934 return FALSE;
8935}
8936
8937/*
8938 * Handle CR or NL in insert mode.
8939 * Return TRUE when out of memory or can't undo.
8940 */
8941 static int
8942ins_eol(c)
8943 int c;
8944{
8945 int i;
8946
8947 if (echeck_abbr(c + ABBR_OFF))
8948 return FALSE;
8949 if (stop_arrow() == FAIL)
8950 return TRUE;
8951 undisplay_dollar();
8952
8953 /*
8954 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
8955 * character under the cursor. Only push a NUL on the replace stack,
8956 * nothing to put back when the NL is deleted.
8957 */
8958 if ((State & REPLACE_FLAG)
8959#ifdef FEAT_VREPLACE
8960 && !(State & VREPLACE_FLAG)
8961#endif
8962 )
8963 replace_push(NUL);
8964
8965 /*
8966 * In VREPLACE mode, a NL replaces the rest of the line, and starts
8967 * replacing the next line, so we push all of the characters left on the
8968 * line onto the replace stack. This is not done here though, it is done
8969 * in open_line().
8970 */
8971
Bram Moolenaarf193fff2006-04-27 00:02:13 +00008972#ifdef FEAT_VIRTUALEDIT
8973 /* Put cursor on NUL if on the last char and coladd is 1 (happens after
8974 * CTRL-O). */
8975 if (virtual_active() && curwin->w_cursor.coladd > 0)
8976 coladvance(getviscol());
8977#endif
8978
Bram Moolenaar071d4272004-06-13 20:20:40 +00008979#ifdef FEAT_RIGHTLEFT
8980# ifdef FEAT_FKMAP
8981 if (p_altkeymap && p_fkmap)
8982 fkmap(NL);
8983# endif
8984 /* NL in reverse insert will always start in the end of
8985 * current line. */
8986 if (revins_on)
8987 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
8988#endif
8989
8990 AppendToRedobuff(NL_STR);
8991 i = open_line(FORWARD,
8992#ifdef FEAT_COMMENTS
8993 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
8994#endif
8995 0, old_indent);
8996 old_indent = 0;
8997#ifdef FEAT_CINDENT
8998 can_cindent = TRUE;
8999#endif
9000
9001 return (!i);
9002}
9003
9004#ifdef FEAT_DIGRAPHS
9005/*
9006 * Handle digraph in insert mode.
9007 * Returns character still to be inserted, or NUL when nothing remaining to be
9008 * done.
9009 */
9010 static int
9011ins_digraph()
9012{
9013 int c;
9014 int cc;
9015
9016 pc_status = PC_STATUS_UNSET;
9017 if (redrawing() && !char_avail())
9018 {
9019 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00009020 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009021
9022 edit_putchar('?', TRUE);
9023#ifdef FEAT_CMDL_INFO
9024 add_to_showcmd_c(Ctrl_K);
9025#endif
9026 }
9027
9028#ifdef USE_ON_FLY_SCROLL
9029 dont_scroll = TRUE; /* disallow scrolling here */
9030#endif
9031
9032 /* don't map the digraph chars. This also prevents the
9033 * mode message to be deleted when ESC is hit */
9034 ++no_mapping;
9035 ++allow_keys;
9036 c = safe_vgetc();
9037 --no_mapping;
9038 --allow_keys;
9039 if (IS_SPECIAL(c) || mod_mask) /* special key */
9040 {
9041#ifdef FEAT_CMDL_INFO
9042 clear_showcmd();
9043#endif
9044 insert_special(c, TRUE, FALSE);
9045 return NUL;
9046 }
9047 if (c != ESC)
9048 {
9049 if (redrawing() && !char_avail())
9050 {
9051 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00009052 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009053
9054 if (char2cells(c) == 1)
9055 {
9056 /* first remove the '?', otherwise it's restored when typing
9057 * an ESC next */
9058 edit_unputchar();
Bram Moolenaar754b5602006-02-09 23:53:20 +00009059 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009060 edit_putchar(c, TRUE);
9061 }
9062#ifdef FEAT_CMDL_INFO
9063 add_to_showcmd_c(c);
9064#endif
9065 }
9066 ++no_mapping;
9067 ++allow_keys;
9068 cc = safe_vgetc();
9069 --no_mapping;
9070 --allow_keys;
9071 if (cc != ESC)
9072 {
9073 AppendToRedobuff((char_u *)CTRL_V_STR);
9074 c = getdigraph(c, cc, TRUE);
9075#ifdef FEAT_CMDL_INFO
9076 clear_showcmd();
9077#endif
9078 return c;
9079 }
9080 }
9081 edit_unputchar();
9082#ifdef FEAT_CMDL_INFO
9083 clear_showcmd();
9084#endif
9085 return NUL;
9086}
9087#endif
9088
9089/*
9090 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
9091 * Returns the char to be inserted, or NUL if none found.
9092 */
9093 static int
9094ins_copychar(lnum)
9095 linenr_T lnum;
9096{
9097 int c;
9098 int temp;
9099 char_u *ptr, *prev_ptr;
9100
9101 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
9102 {
9103 vim_beep();
9104 return NUL;
9105 }
9106
9107 /* try to advance to the cursor column */
9108 temp = 0;
9109 ptr = ml_get(lnum);
9110 prev_ptr = ptr;
9111 validate_virtcol();
9112 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
9113 {
9114 prev_ptr = ptr;
9115 temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
9116 }
9117 if ((colnr_T)temp > curwin->w_virtcol)
9118 ptr = prev_ptr;
9119
9120#ifdef FEAT_MBYTE
9121 c = (*mb_ptr2char)(ptr);
9122#else
9123 c = *ptr;
9124#endif
9125 if (c == NUL)
9126 vim_beep();
9127 return c;
9128}
9129
Bram Moolenaar4be06f92005-07-29 22:36:03 +00009130/*
9131 * CTRL-Y or CTRL-E typed in Insert mode.
9132 */
9133 static int
9134ins_ctrl_ey(tc)
9135 int tc;
9136{
9137 int c = tc;
9138
9139#ifdef FEAT_INS_EXPAND
9140 if (ctrl_x_mode == CTRL_X_SCROLL)
9141 {
9142 if (c == Ctrl_Y)
9143 scrolldown_clamp();
9144 else
9145 scrollup_clamp();
9146 redraw_later(VALID);
9147 }
9148 else
9149#endif
9150 {
9151 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
9152 if (c != NUL)
9153 {
9154 long tw_save;
9155
9156 /* The character must be taken literally, insert like it
9157 * was typed after a CTRL-V, and pretend 'textwidth'
9158 * wasn't set. Digits, 'o' and 'x' are special after a
9159 * CTRL-V, don't use it for these. */
9160 if (c < 256 && !isalnum(c))
9161 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
9162 tw_save = curbuf->b_p_tw;
9163 curbuf->b_p_tw = -1;
9164 insert_special(c, TRUE, FALSE);
9165 curbuf->b_p_tw = tw_save;
9166#ifdef FEAT_RIGHTLEFT
9167 revins_chars++;
9168 revins_legal++;
9169#endif
9170 c = Ctrl_V; /* pretend CTRL-V is last character */
9171 auto_format(FALSE, TRUE);
9172 }
9173 }
9174 return c;
9175}
9176
Bram Moolenaar071d4272004-06-13 20:20:40 +00009177#ifdef FEAT_SMARTINDENT
9178/*
9179 * Try to do some very smart auto-indenting.
9180 * Used when inserting a "normal" character.
9181 */
9182 static void
9183ins_try_si(c)
9184 int c;
9185{
9186 pos_T *pos, old_pos;
9187 char_u *ptr;
9188 int i;
9189 int temp;
9190
9191 /*
9192 * do some very smart indenting when entering '{' or '}'
9193 */
9194 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
9195 {
9196 /*
9197 * for '}' set indent equal to indent of line containing matching '{'
9198 */
9199 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
9200 {
9201 old_pos = curwin->w_cursor;
9202 /*
9203 * If the matching '{' has a ')' immediately before it (ignoring
9204 * white-space), then line up with the start of the line
9205 * containing the matching '(' if there is one. This handles the
9206 * case where an "if (..\n..) {" statement continues over multiple
9207 * lines -- webb
9208 */
9209 ptr = ml_get(pos->lnum);
9210 i = pos->col;
9211 if (i > 0) /* skip blanks before '{' */
9212 while (--i > 0 && vim_iswhite(ptr[i]))
9213 ;
9214 curwin->w_cursor.lnum = pos->lnum;
9215 curwin->w_cursor.col = i;
9216 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
9217 curwin->w_cursor = *pos;
9218 i = get_indent();
9219 curwin->w_cursor = old_pos;
9220#ifdef FEAT_VREPLACE
9221 if (State & VREPLACE_FLAG)
9222 change_indent(INDENT_SET, i, FALSE, NUL);
9223 else
9224#endif
9225 (void)set_indent(i, SIN_CHANGED);
9226 }
9227 else if (curwin->w_cursor.col > 0)
9228 {
9229 /*
9230 * when inserting '{' after "O" reduce indent, but not
9231 * more than indent of previous line
9232 */
9233 temp = TRUE;
9234 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
9235 {
9236 old_pos = curwin->w_cursor;
9237 i = get_indent();
9238 while (curwin->w_cursor.lnum > 1)
9239 {
9240 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
9241
9242 /* ignore empty lines and lines starting with '#'. */
9243 if (*ptr != '#' && *ptr != NUL)
9244 break;
9245 }
9246 if (get_indent() >= i)
9247 temp = FALSE;
9248 curwin->w_cursor = old_pos;
9249 }
9250 if (temp)
9251 shift_line(TRUE, FALSE, 1);
9252 }
9253 }
9254
9255 /*
9256 * set indent of '#' always to 0
9257 */
9258 if (curwin->w_cursor.col > 0 && can_si && c == '#')
9259 {
9260 /* remember current indent for next line */
9261 old_indent = get_indent();
9262 (void)set_indent(0, SIN_CHANGED);
9263 }
9264
9265 /* Adjust ai_col, the char at this position can be deleted. */
9266 if (ai_col > curwin->w_cursor.col)
9267 ai_col = curwin->w_cursor.col;
9268}
9269#endif
9270
9271/*
9272 * Get the value that w_virtcol would have when 'list' is off.
9273 * Unless 'cpo' contains the 'L' flag.
9274 */
9275 static colnr_T
9276get_nolist_virtcol()
9277{
9278 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
9279 return getvcol_nolist(&curwin->w_cursor);
9280 validate_virtcol();
9281 return curwin->w_virtcol;
9282}