blob: f30b59d1858f5c1b4d6207bbb130d801a01347a0 [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 Moolenaar1423b9d2006-05-07 15:16:06 +0000108static int compl_was_interrupted = FALSE; /* didn't finish finding
109 completions. */
110
111static int compl_restarting = FALSE; /* don't insert match */
112
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000113/* When the first completion is done "compl_started" is set. When it's
114 * FALSE the word to be completed must be located. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000115static int compl_started = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000116
Bram Moolenaar572cb562005-08-05 21:35:02 +0000117static int compl_matches = 0;
118static char_u *compl_pattern = NULL;
119static int compl_direction = FORWARD;
120static int compl_shows_dir = FORWARD;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000121static int compl_pending = 0; /* > 1 for postponed CTRL-N */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000122static pos_T compl_startpos;
123static colnr_T compl_col = 0; /* column where the text starts
124 * that is being completed */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000125static char_u *compl_orig_text = NULL; /* text as it was before
126 * completion started */
127static int compl_cont_mode = 0;
128static expand_T compl_xp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000130static void ins_ctrl_x __ARGS((void));
131static int has_compl_option __ARGS((int dict_opt));
Bram Moolenaar4a85b412006-04-23 22:40:29 +0000132static 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 +0000133static int ins_compl_equal __ARGS((compl_T *match, char_u *str, int len));
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000134static void ins_compl_longest_match __ARGS((compl_T *match));
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000135static void ins_compl_add_matches __ARGS((int num_matches, char_u **matches, int icase));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136static int ins_compl_make_cyclic __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000137static void ins_compl_upd_pum __ARGS((void));
138static void ins_compl_del_pum __ARGS((void));
Bram Moolenaar280f1262006-01-30 00:14:18 +0000139static int pum_wanted __ARGS((void));
Bram Moolenaar65c923a2006-03-03 22:56:30 +0000140static int pum_enough_matches __ARGS((void));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000141static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int flags, int thesaurus));
Bram Moolenaar0b238792006-03-02 22:49:12 +0000142static 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 +0000143static char_u *find_line_end __ARGS((char_u *ptr));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144static void ins_compl_free __ARGS((void));
145static void ins_compl_clear __ARGS((void));
Bram Moolenaara6557602006-02-04 22:43:20 +0000146static int ins_compl_bs __ARGS((void));
Bram Moolenaar1423b9d2006-05-07 15:16:06 +0000147static void ins_compl_new_leader __ARGS((void));
Bram Moolenaara6557602006-02-04 22:43:20 +0000148static void ins_compl_addleader __ARGS((int c));
Bram Moolenaar1423b9d2006-05-07 15:16:06 +0000149static void ins_compl_restart __ARGS((void));
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000150static void ins_compl_set_original_text __ARGS((char_u *str));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000151static void ins_compl_addfrommatch __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000152static int ins_compl_prep __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));
Bram Moolenaara94bc432006-03-10 21:42:59 +0000154#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
155static void ins_compl_add_list __ARGS((list_T *list));
156#endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000157static int ins_compl_get_exp __ARGS((pos_T *ini));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158static void ins_compl_delete __ARGS((void));
159static void ins_compl_insert __ARGS((void));
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000160static int ins_compl_next __ARGS((int allow_get_expansion, int count, int insert_match));
Bram Moolenaare3226be2005-12-18 22:10:00 +0000161static int ins_compl_key2dir __ARGS((int c));
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000162static int ins_compl_pum_key __ARGS((int c));
Bram Moolenaare3226be2005-12-18 22:10:00 +0000163static int ins_compl_key2count __ARGS((int c));
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000164static int ins_compl_use_match __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165static int ins_complete __ARGS((int c));
166static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
167#endif /* FEAT_INS_EXPAND */
168
169#define BACKSPACE_CHAR 1
170#define BACKSPACE_WORD 2
171#define BACKSPACE_WORD_NOT_SPACE 3
172#define BACKSPACE_LINE 4
173
Bram Moolenaar754b5602006-02-09 23:53:20 +0000174static void ins_redraw __ARGS((int ready));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175static void ins_ctrl_v __ARGS((void));
176static void undisplay_dollar __ARGS((void));
177static void insert_special __ARGS((int, int, int));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000178static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179static void check_auto_format __ARGS((int));
180static void redo_literal __ARGS((int c));
181static void start_arrow __ARGS((pos_T *end_insert_pos));
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000182#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +0000183static void check_spell_redraw __ARGS((void));
Bram Moolenaar8aff23a2005-08-19 20:40:30 +0000184static void spell_back_to_badword __ARGS((void));
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +0000185static int spell_bad_len = 0; /* length of located bad word */
Bram Moolenaar217ad922005-03-20 22:37:15 +0000186#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187static void stop_insert __ARGS((pos_T *end_insert_pos, int esc));
188static int echeck_abbr __ARGS((int));
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000189#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190static void replace_push_off __ARGS((int c));
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000191#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192static int replace_pop __ARGS((void));
193static void replace_join __ARGS((int off));
194static void replace_pop_ins __ARGS((void));
195#ifdef FEAT_MBYTE
196static void mb_replace_pop_ins __ARGS((int cc));
197#endif
198static void replace_flush __ARGS((void));
199static void replace_do_bs __ARGS((void));
200#ifdef FEAT_CINDENT
201static int cindent_on __ARGS((void));
202#endif
203static void ins_reg __ARGS((void));
204static void ins_ctrl_g __ARGS((void));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000205static void ins_ctrl_hat __ARGS((void));
Bram Moolenaar488c6512005-08-11 20:09:58 +0000206static int ins_esc __ARGS((long *count, int cmdchar, int nomove));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207#ifdef FEAT_RIGHTLEFT
208static void ins_ctrl_ __ARGS((void));
209#endif
210#ifdef FEAT_VISUAL
211static int ins_start_select __ARGS((int c));
212#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000213static void ins_insert __ARGS((int replaceState));
214static void ins_ctrl_o __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215static void ins_shift __ARGS((int c, int lastc));
216static void ins_del __ARGS((void));
217static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
218#ifdef FEAT_MOUSE
219static void ins_mouse __ARGS((int c));
220static void ins_mousescroll __ARGS((int up));
221#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +0000222#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
223static void ins_tabline __ARGS((int c));
224#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225static void ins_left __ARGS((void));
226static void ins_home __ARGS((int c));
227static void ins_end __ARGS((int c));
228static void ins_s_left __ARGS((void));
229static void ins_right __ARGS((void));
230static void ins_s_right __ARGS((void));
231static void ins_up __ARGS((int startcol));
232static void ins_pageup __ARGS((void));
233static void ins_down __ARGS((int startcol));
234static void ins_pagedown __ARGS((void));
235#ifdef FEAT_DND
236static void ins_drop __ARGS((void));
237#endif
238static int ins_tab __ARGS((void));
239static int ins_eol __ARGS((int c));
240#ifdef FEAT_DIGRAPHS
241static int ins_digraph __ARGS((void));
242#endif
243static int ins_copychar __ARGS((linenr_T lnum));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000244static int ins_ctrl_ey __ARGS((int tc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245#ifdef FEAT_SMARTINDENT
246static void ins_try_si __ARGS((int c));
247#endif
248static colnr_T get_nolist_virtcol __ARGS((void));
249
250static colnr_T Insstart_textlen; /* length of line when insert started */
251static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
252
253static char_u *last_insert = NULL; /* the text of the previous insert,
254 K_SPECIAL and CSI are escaped */
255static int last_insert_skip; /* nr of chars in front of previous insert */
256static int new_insert_skip; /* nr of chars in front of current insert */
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000257static int did_restart_edit; /* "restart_edit" when calling edit() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258
259#ifdef FEAT_CINDENT
260static int can_cindent; /* may do cindenting on this line */
261#endif
262
263static int old_indent = 0; /* for ^^D command in insert mode */
264
265#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +0000266static int revins_on; /* reverse insert mode on */
267static int revins_chars; /* how much to skip after edit */
268static int revins_legal; /* was the last char 'legal'? */
269static int revins_scol; /* start column of revins session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270#endif
271
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272static int ins_need_undo; /* call u_save() before inserting a
273 char. Set when edit() is called.
274 after that arrow_used is used. */
275
276static int did_add_space = FALSE; /* auto_format() added an extra space
277 under the cursor */
278
279/*
280 * edit(): Start inserting text.
281 *
282 * "cmdchar" can be:
283 * 'i' normal insert command
284 * 'a' normal append command
285 * 'R' replace command
286 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
287 * but still only one <CR> is inserted. The <Esc> is not used for redo.
288 * 'g' "gI" command.
289 * 'V' "gR" command for Virtual Replace mode.
290 * 'v' "gr" command for single character Virtual Replace mode.
291 *
292 * This function is not called recursively. For CTRL-O commands, it returns
293 * and lets the caller handle the Normal-mode command.
294 *
295 * Return TRUE if a CTRL-O command caused the return (insert mode pending).
296 */
297 int
298edit(cmdchar, startln, count)
299 int cmdchar;
300 int startln; /* if set, insert at start of line */
301 long count;
302{
303 int c = 0;
304 char_u *ptr;
305 int lastc;
306 colnr_T mincol;
307 static linenr_T o_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 int i;
309 int did_backspace = TRUE; /* previous char was backspace */
310#ifdef FEAT_CINDENT
311 int line_is_white = FALSE; /* line is empty before insert */
312#endif
313 linenr_T old_topline = 0; /* topline before insertion */
314#ifdef FEAT_DIFF
315 int old_topfill = -1;
316#endif
317 int inserted_space = FALSE; /* just inserted a space */
318 int replaceState = REPLACE;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000319 int nomove = FALSE; /* don't move cursor on return */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000321 /* Remember whether editing was restarted after CTRL-O. */
322 did_restart_edit = restart_edit;
323
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324 /* sleep before redrawing, needed for "CTRL-O :" that results in an
325 * error message */
326 check_for_delay(TRUE);
327
328#ifdef HAVE_SANDBOX
329 /* Don't allow inserting in the sandbox. */
330 if (sandbox != 0)
331 {
332 EMSG(_(e_sandbox));
333 return FALSE;
334 }
335#endif
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000336 /* Don't allow changes in the buffer while editing the cmdline. The
337 * caller of getcmdline() may get confused. */
Bram Moolenaarb71eaae2006-01-20 23:10:18 +0000338 if (textlock != 0)
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000339 {
340 EMSG(_(e_secure));
341 return FALSE;
342 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343
344#ifdef FEAT_INS_EXPAND
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000345 /* Don't allow recursive insert mode when busy with completion. */
346 if (compl_started || pum_visible())
347 {
348 EMSG(_(e_secure));
349 return FALSE;
350 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000351 ins_compl_clear(); /* clear stuff for CTRL-X mode */
352#endif
353
Bram Moolenaar843ee412004-06-30 16:16:41 +0000354#ifdef FEAT_AUTOCMD
355 /*
356 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
357 */
358 if (cmdchar != 'r' && cmdchar != 'v')
359 {
Bram Moolenaar1e015462005-09-25 22:16:38 +0000360# ifdef FEAT_EVAL
Bram Moolenaar843ee412004-06-30 16:16:41 +0000361 if (cmdchar == 'R')
362 ptr = (char_u *)"r";
363 else if (cmdchar == 'V')
364 ptr = (char_u *)"v";
365 else
366 ptr = (char_u *)"i";
367 set_vim_var_string(VV_INSERTMODE, ptr, 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +0000368# endif
Bram Moolenaar843ee412004-06-30 16:16:41 +0000369 apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);
370 }
371#endif
372
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373#ifdef FEAT_MOUSE
374 /*
375 * When doing a paste with the middle mouse button, Insstart is set to
376 * where the paste started.
377 */
378 if (where_paste_started.lnum != 0)
379 Insstart = where_paste_started;
380 else
381#endif
382 {
383 Insstart = curwin->w_cursor;
384 if (startln)
385 Insstart.col = 0;
386 }
387 Insstart_textlen = linetabsize(ml_get_curline());
388 Insstart_blank_vcol = MAXCOL;
389 if (!did_ai)
390 ai_col = 0;
391
392 if (cmdchar != NUL && restart_edit == 0)
393 {
394 ResetRedobuff();
395 AppendNumberToRedobuff(count);
396#ifdef FEAT_VREPLACE
397 if (cmdchar == 'V' || cmdchar == 'v')
398 {
399 /* "gR" or "gr" command */
400 AppendCharToRedobuff('g');
401 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
402 }
403 else
404#endif
405 {
406 AppendCharToRedobuff(cmdchar);
407 if (cmdchar == 'g') /* "gI" command */
408 AppendCharToRedobuff('I');
409 else if (cmdchar == 'r') /* "r<CR>" command */
410 count = 1; /* insert only one <CR> */
411 }
412 }
413
414 if (cmdchar == 'R')
415 {
416#ifdef FEAT_FKMAP
417 if (p_fkmap && p_ri)
418 {
419 beep_flush();
420 EMSG(farsi_text_3); /* encoded in Farsi */
421 State = INSERT;
422 }
423 else
424#endif
425 State = REPLACE;
426 }
427#ifdef FEAT_VREPLACE
428 else if (cmdchar == 'V' || cmdchar == 'v')
429 {
430 State = VREPLACE;
431 replaceState = VREPLACE;
432 orig_line_count = curbuf->b_ml.ml_line_count;
433 vr_lines_changed = 1;
434 }
435#endif
436 else
437 State = INSERT;
438
439 stop_insert_mode = FALSE;
440
441 /*
442 * Need to recompute the cursor position, it might move when the cursor is
443 * on a TAB or special character.
444 */
445 curs_columns(TRUE);
446
447 /*
448 * Enable langmap or IME, indicated by 'iminsert'.
449 * Note that IME may enabled/disabled without us noticing here, thus the
450 * 'iminsert' value may not reflect what is actually used. It is updated
451 * when hitting <Esc>.
452 */
453 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
454 State |= LANGMAP;
455#ifdef USE_IM_CONTROL
456 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
457#endif
458
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459#ifdef FEAT_MOUSE
460 setmouse();
461#endif
462#ifdef FEAT_CMDL_INFO
463 clear_showcmd();
464#endif
465#ifdef FEAT_RIGHTLEFT
466 /* there is no reverse replace mode */
467 revins_on = (State == INSERT && p_ri);
468 if (revins_on)
469 undisplay_dollar();
470 revins_chars = 0;
471 revins_legal = 0;
472 revins_scol = -1;
473#endif
474
475 /*
476 * Handle restarting Insert mode.
477 * Don't do this for "CTRL-O ." (repeat an insert): we get here with
478 * restart_edit non-zero, and something in the stuff buffer.
479 */
480 if (restart_edit != 0 && stuff_empty())
481 {
482#ifdef FEAT_MOUSE
483 /*
484 * After a paste we consider text typed to be part of the insert for
485 * the pasted text. You can backspace over the pasted text too.
486 */
487 if (where_paste_started.lnum)
488 arrow_used = FALSE;
489 else
490#endif
491 arrow_used = TRUE;
492 restart_edit = 0;
493
494 /*
495 * If the cursor was after the end-of-line before the CTRL-O and it is
496 * now at the end-of-line, put it after the end-of-line (this is not
497 * correct in very rare cases).
498 * Also do this if curswant is greater than the current virtual
499 * column. Eg after "^O$" or "^O80|".
500 */
501 validate_virtcol();
502 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000503 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 || curwin->w_curswant > curwin->w_virtcol)
505 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
506 {
507 if (ptr[1] == NUL)
508 ++curwin->w_cursor.col;
509#ifdef FEAT_MBYTE
510 else if (has_mbyte)
511 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000512 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 if (ptr[i] == NUL)
514 curwin->w_cursor.col += i;
515 }
516#endif
517 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000518 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 }
520 else
521 arrow_used = FALSE;
522
523 /* we are in insert mode now, don't need to start it anymore */
524 need_start_insertmode = FALSE;
525
526 /* Need to save the line for undo before inserting the first char. */
527 ins_need_undo = TRUE;
528
529#ifdef FEAT_MOUSE
530 where_paste_started.lnum = 0;
531#endif
532#ifdef FEAT_CINDENT
533 can_cindent = TRUE;
534#endif
535#ifdef FEAT_FOLDING
536 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
537 * restarting. */
538 if (!p_im && did_restart_edit == 0)
539 foldOpenCursor();
540#endif
541
542 /*
543 * If 'showmode' is set, show the current (insert/replace/..) mode.
544 * A warning message for changing a readonly file is given here, before
545 * actually changing anything. It's put after the mode, if any.
546 */
547 i = 0;
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000548 if (p_smd && msg_silent == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 i = showmode();
550
551 if (!p_im && did_restart_edit == 0)
552 change_warning(i + 1);
553
554#ifdef CURSOR_SHAPE
555 ui_cursor_shape(); /* may show different cursor shape */
556#endif
557#ifdef FEAT_DIGRAPHS
558 do_digraph(-1); /* clear digraphs */
559#endif
560
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000561 /*
562 * Get the current length of the redo buffer, those characters have to be
563 * skipped if we want to get to the inserted characters.
564 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 ptr = get_inserted();
566 if (ptr == NULL)
567 new_insert_skip = 0;
568 else
569 {
570 new_insert_skip = (int)STRLEN(ptr);
571 vim_free(ptr);
572 }
573
574 old_indent = 0;
575
576 /*
577 * Main loop in Insert mode: repeat until Insert mode is left.
578 */
579 for (;;)
580 {
581#ifdef FEAT_RIGHTLEFT
582 if (!revins_legal)
583 revins_scol = -1; /* reset on illegal motions */
584 else
585 revins_legal = 0;
586#endif
587 if (arrow_used) /* don't repeat insert when arrow key used */
588 count = 0;
589
590 if (stop_insert_mode)
591 {
592 /* ":stopinsert" used or 'insertmode' reset */
593 count = 0;
594 goto doESCkey;
595 }
596
597 /* set curwin->w_curswant for next K_DOWN or K_UP */
598 if (!arrow_used)
599 curwin->w_set_curswant = TRUE;
600
601 /* If there is no typeahead may check for timestamps (e.g., for when a
602 * menu invoked a shell command). */
603 if (stuff_empty())
604 {
605 did_check_timestamps = FALSE;
606 if (need_check_timestamps)
607 check_timestamps(FALSE);
608 }
609
610 /*
611 * When emsg() was called msg_scroll will have been set.
612 */
613 msg_scroll = FALSE;
614
615#ifdef FEAT_GUI
616 /* When 'mousefocus' is set a mouse movement may have taken us to
617 * another window. "need_mouse_correct" may then be set because of an
618 * autocommand. */
619 if (need_mouse_correct)
620 gui_mouse_correct();
621#endif
622
623#ifdef FEAT_FOLDING
624 /* Open fold at the cursor line, according to 'foldopen'. */
625 if (fdo_flags & FDO_INSERT)
626 foldOpenCursor();
627 /* Close folds where the cursor isn't, according to 'foldclose' */
628 if (!char_avail())
629 foldCheckClose();
630#endif
631
632 /*
633 * If we inserted a character at the last position of the last line in
634 * the window, scroll the window one line up. This avoids an extra
635 * redraw.
636 * This is detected when the cursor column is smaller after inserting
637 * something.
638 * Don't do this when the topline changed already, it has
639 * already been adjusted (by insertchar() calling open_line())).
640 */
641 if (curbuf->b_mod_set
642 && curwin->w_p_wrap
643 && !did_backspace
644 && curwin->w_topline == old_topline
645#ifdef FEAT_DIFF
646 && curwin->w_topfill == old_topfill
647#endif
648 )
649 {
650 mincol = curwin->w_wcol;
651 validate_cursor_col();
652
653 if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts
654 && curwin->w_wrow == W_WINROW(curwin)
655 + curwin->w_height - 1 - p_so
656 && (curwin->w_cursor.lnum != curwin->w_topline
657#ifdef FEAT_DIFF
658 || curwin->w_topfill > 0
659#endif
660 ))
661 {
662#ifdef FEAT_DIFF
663 if (curwin->w_topfill > 0)
664 --curwin->w_topfill;
665 else
666#endif
667#ifdef FEAT_FOLDING
668 if (hasFolding(curwin->w_topline, NULL, &old_topline))
669 set_topline(curwin, old_topline + 1);
670 else
671#endif
672 set_topline(curwin, curwin->w_topline + 1);
673 }
674 }
675
676 /* May need to adjust w_topline to show the cursor. */
677 update_topline();
678
679 did_backspace = FALSE;
680
681 validate_cursor(); /* may set must_redraw */
682
683 /*
684 * Redraw the display when no characters are waiting.
685 * Also shows mode, ruler and positions cursor.
686 */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000687 ins_redraw(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000688
689#ifdef FEAT_SCROLLBIND
690 if (curwin->w_p_scb)
691 do_check_scrollbind(TRUE);
692#endif
693
694 update_curswant();
695 old_topline = curwin->w_topline;
696#ifdef FEAT_DIFF
697 old_topfill = curwin->w_topfill;
698#endif
699
700#ifdef USE_ON_FLY_SCROLL
701 dont_scroll = FALSE; /* allow scrolling here */
702#endif
703
704 /*
705 * Get a character for Insert mode.
706 */
707 lastc = c; /* remember previous char for CTRL-D */
708 c = safe_vgetc();
709
710#ifdef FEAT_RIGHTLEFT
711 if (p_hkmap && KeyTyped)
712 c = hkmap(c); /* Hebrew mode mapping */
713#endif
714#ifdef FEAT_FKMAP
715 if (p_fkmap && KeyTyped)
716 c = fkmap(c); /* Farsi mode mapping */
717#endif
718
719#ifdef FEAT_INS_EXPAND
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000720 /*
721 * Special handling of keys while the popup menu is visible or wanted
722 * and the cursor is still in the completed word.
723 */
724 if (compl_started && pum_wanted() && curwin->w_cursor.col >= compl_col)
Bram Moolenaara6557602006-02-04 22:43:20 +0000725 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000726 /* BS: Delete one character from "compl_leader". */
727 if ((c == K_BS || c == Ctrl_H)
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000728 && curwin->w_cursor.col > compl_col
729 && (c = ins_compl_bs()) == NUL)
Bram Moolenaara6557602006-02-04 22:43:20 +0000730 continue;
731
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000732 /* When no match was selected or it was edited. */
733 if (!compl_used_match)
Bram Moolenaara6557602006-02-04 22:43:20 +0000734 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000735 /* CTRL-L: Add one character from the current match to
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000736 * "compl_leader". Except when at the original match and
737 * there is nothing to add, CTRL-L works like CTRL-P then. */
738 if (c == Ctrl_L
739 && (ctrl_x_mode != CTRL_X_WHOLE_LINE
740 || STRLEN(compl_shown_match->cp_str)
741 > curwin->w_cursor.col - compl_col))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000742 {
743 ins_compl_addfrommatch();
744 continue;
745 }
746
Bram Moolenaardf1bdc92006-02-23 21:32:16 +0000747 /* A printable, non-white character: Add to "compl_leader". */
748 if (vim_isprintc(c) && !vim_iswhite(c))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000749 {
750 ins_compl_addleader(c);
751 continue;
752 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000753
Bram Moolenaar0440ca32006-05-13 13:24:33 +0000754 /* Pressing CTRL-Y selects the current match. When
Bram Moolenaar779b74b2006-04-10 14:55:34 +0000755 * compl_enter_selects is set the Enter key does the same. */
756 if (c == Ctrl_Y || (compl_enter_selects
757 && (c == CAR || c == K_KENTER || c == NL)))
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000758 {
759 ins_compl_delete();
760 ins_compl_insert();
761 }
Bram Moolenaara6557602006-02-04 22:43:20 +0000762 }
763 }
764
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
766 * it does fix up the text when finishing completion. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000767 compl_get_longest = FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +0000768 if (c != K_IGNORE && ins_compl_prep(c))
769 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770#endif
771
Bram Moolenaar488c6512005-08-11 20:09:58 +0000772 /* CTRL-\ CTRL-N goes to Normal mode,
773 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
774 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 if (c == Ctrl_BSL)
776 {
777 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000778 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 ++no_mapping;
780 ++allow_keys;
781 c = safe_vgetc();
782 --no_mapping;
783 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000784 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000786 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 vungetc(c);
788 c = Ctrl_BSL;
789 }
790 else if (c == Ctrl_G && p_im)
791 continue;
792 else
793 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000794 if (c == Ctrl_O)
795 {
796 ins_ctrl_o();
797 ins_at_eol = FALSE; /* cursor keeps its column */
798 nomove = TRUE;
799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 count = 0;
801 goto doESCkey;
802 }
803 }
804
805#ifdef FEAT_DIGRAPHS
806 c = do_digraph(c);
807#endif
808
809#ifdef FEAT_INS_EXPAND
810 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
811 goto docomplete;
812#endif
813 if (c == Ctrl_V || c == Ctrl_Q)
814 {
815 ins_ctrl_v();
816 c = Ctrl_V; /* pretend CTRL-V is last typed character */
817 continue;
818 }
819
820#ifdef FEAT_CINDENT
821 if (cindent_on()
822# ifdef FEAT_INS_EXPAND
823 && ctrl_x_mode == 0
824# endif
825 )
826 {
827 /* A key name preceded by a bang means this key is not to be
828 * inserted. Skip ahead to the re-indenting below.
829 * A key name preceded by a star means that indenting has to be
830 * done before inserting the key. */
831 line_is_white = inindent(0);
832 if (in_cinkeys(c, '!', line_is_white))
833 goto force_cindent;
834 if (can_cindent && in_cinkeys(c, '*', line_is_white)
835 && stop_arrow() == OK)
836 do_c_expr_indent();
837 }
838#endif
839
840#ifdef FEAT_RIGHTLEFT
841 if (curwin->w_p_rl)
842 switch (c)
843 {
844 case K_LEFT: c = K_RIGHT; break;
845 case K_S_LEFT: c = K_S_RIGHT; break;
846 case K_C_LEFT: c = K_C_RIGHT; break;
847 case K_RIGHT: c = K_LEFT; break;
848 case K_S_RIGHT: c = K_S_LEFT; break;
849 case K_C_RIGHT: c = K_C_LEFT; break;
850 }
851#endif
852
853#ifdef FEAT_VISUAL
854 /*
855 * If 'keymodel' contains "startsel", may start selection. If it
856 * does, a CTRL-O and c will be stuffed, we need to get these
857 * characters.
858 */
859 if (ins_start_select(c))
860 continue;
861#endif
862
863 /*
864 * The big switch to handle a character in insert mode.
865 */
866 switch (c)
867 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000868 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 if (echeck_abbr(ESC + ABBR_OFF))
870 break;
871 /*FALLTHROUGH*/
872
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000873 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874#ifdef FEAT_CMDWIN
875 if (c == Ctrl_C && cmdwin_type != 0)
876 {
877 /* Close the cmdline window. */
878 cmdwin_result = K_IGNORE;
879 got_int = FALSE; /* don't stop executing autocommands et al. */
880 goto doESCkey;
881 }
882#endif
883
884#ifdef UNIX
885do_intr:
886#endif
887 /* when 'insertmode' set, and not halfway a mapping, don't leave
888 * Insert mode */
889 if (goto_im())
890 {
891 if (got_int)
892 {
893 (void)vgetc(); /* flush all buffers */
894 got_int = FALSE;
895 }
896 else
897 vim_beep();
898 break;
899 }
900doESCkey:
901 /*
902 * This is the ONLY return from edit()!
903 */
904 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
905 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000906 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 o_lnum = curwin->w_cursor.lnum;
908
Bram Moolenaar488c6512005-08-11 20:09:58 +0000909 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000910 {
911#ifdef FEAT_AUTOCMD
912 if (cmdchar != 'r' && cmdchar != 'v')
913 apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL,
914 FALSE, curbuf);
915#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000917 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 continue;
919
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000920 case Ctrl_Z: /* suspend when 'insertmode' set */
921 if (!p_im)
922 goto normalchar; /* insert CTRL-Z as normal char */
923 stuffReadbuff((char_u *)":st\r");
924 c = Ctrl_O;
925 /*FALLTHROUGH*/
926
927 case Ctrl_O: /* execute one command */
Bram Moolenaare344bea2005-09-01 20:46:49 +0000928#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000929 if (ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000930 goto docomplete;
931#endif
932 if (echeck_abbr(Ctrl_O + ABBR_OFF))
933 break;
934 ins_ctrl_o();
Bram Moolenaar06a89a52006-04-29 22:01:03 +0000935
936#ifdef FEAT_VIRTUALEDIT
937 /* don't move the cursor left when 'virtualedit' has "onemore". */
938 if (ve_flags & VE_ONEMORE)
939 {
940 ins_at_eol = FALSE;
941 nomove = TRUE;
942 }
943#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000944 count = 0;
945 goto doESCkey;
946
Bram Moolenaar572cb562005-08-05 21:35:02 +0000947 case K_INS: /* toggle insert/replace mode */
948 case K_KINS:
949 ins_insert(replaceState);
950 break;
951
952 case K_SELECT: /* end of Select mode mapping - ignore */
953 break;
954
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000955#ifdef FEAT_SNIFF
956 case K_SNIFF: /* Sniff command received */
957 stuffcharReadbuff(K_SNIFF);
958 goto doESCkey;
959#endif
960
961 case K_HELP: /* Help key works like <ESC> <Help> */
962 case K_F1:
963 case K_XF1:
964 stuffcharReadbuff(K_HELP);
965 if (p_im)
966 need_start_insertmode = TRUE;
967 goto doESCkey;
968
969#ifdef FEAT_NETBEANS_INTG
970 case K_F21: /* NetBeans command */
971 ++no_mapping; /* don't map the next key hits */
972 i = safe_vgetc();
973 --no_mapping;
974 netbeans_keycommand(i);
975 break;
976#endif
977
978 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 case NUL:
980 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000981 /* For ^@ the trailing ESC will end the insert, unless there is an
982 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
984 && c != Ctrl_A && !p_im)
985 goto doESCkey; /* quit insert mode */
986 inserted_space = FALSE;
987 break;
988
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000989 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 ins_reg();
991 auto_format(FALSE, TRUE);
992 inserted_space = FALSE;
993 break;
994
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000995 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 ins_ctrl_g();
997 break;
998
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000999 case Ctrl_HAT: /* switch input mode and/or langmap */
1000 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 break;
1002
1003#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001004 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005 if (!p_ari)
1006 goto normalchar;
1007 ins_ctrl_();
1008 break;
1009#endif
1010
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001011 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1013 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
1014 goto docomplete;
1015#endif
1016 /* FALLTHROUGH */
1017
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001018 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019# ifdef FEAT_INS_EXPAND
1020 if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
1021 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001022 if (has_compl_option(FALSE))
1023 goto docomplete;
1024 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025 }
1026# endif
1027 ins_shift(c, lastc);
1028 auto_format(FALSE, TRUE);
1029 inserted_space = FALSE;
1030 break;
1031
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001032 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 case K_KDEL:
1034 ins_del();
1035 auto_format(FALSE, TRUE);
1036 break;
1037
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001038 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 case Ctrl_H:
1040 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
1041 auto_format(FALSE, TRUE);
1042 break;
1043
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001044 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
1046 auto_format(FALSE, TRUE);
1047 break;
1048
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001049 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001050# ifdef FEAT_COMPL_FUNC
1051 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001052 if (ctrl_x_mode == CTRL_X_FUNCTION)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001053 goto docomplete;
1054# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
1056 auto_format(FALSE, TRUE);
1057 inserted_space = FALSE;
1058 break;
1059
1060#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001061 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 case K_LEFTMOUSE_NM:
1063 case K_LEFTDRAG:
1064 case K_LEFTRELEASE:
1065 case K_LEFTRELEASE_NM:
1066 case K_MIDDLEMOUSE:
1067 case K_MIDDLEDRAG:
1068 case K_MIDDLERELEASE:
1069 case K_RIGHTMOUSE:
1070 case K_RIGHTDRAG:
1071 case K_RIGHTRELEASE:
1072 case K_X1MOUSE:
1073 case K_X1DRAG:
1074 case K_X1RELEASE:
1075 case K_X2MOUSE:
1076 case K_X2DRAG:
1077 case K_X2RELEASE:
1078 ins_mouse(c);
1079 break;
1080
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001081 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 ins_mousescroll(FALSE);
1083 break;
1084
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001085 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 ins_mousescroll(TRUE);
1087 break;
1088#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +00001089#ifdef FEAT_GUI_TABLINE
1090 case K_TABLINE:
1091 case K_TABMENU:
1092 ins_tabline(c);
1093 break;
1094#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001096 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 break;
1098
Bram Moolenaar754b5602006-02-09 23:53:20 +00001099#ifdef FEAT_AUTOCMD
1100 case K_CURSORHOLD: /* Didn't type something for a while. */
1101 apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf);
1102 did_cursorhold = TRUE;
1103 break;
1104#endif
1105
Bram Moolenaar4770d092006-01-12 23:22:24 +00001106#ifdef FEAT_GUI_W32
1107 /* On Win32 ignore <M-F4>, we get it when closing the window was
1108 * cancelled. */
1109 case K_F4:
1110 if (mod_mask != MOD_MASK_ALT)
1111 goto normalchar;
1112 break;
1113#endif
1114
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115#ifdef FEAT_GUI
1116 case K_VER_SCROLLBAR:
1117 ins_scroll();
1118 break;
1119
1120 case K_HOR_SCROLLBAR:
1121 ins_horscroll();
1122 break;
1123#endif
1124
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001125 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 case K_S_HOME:
1128 case K_C_HOME:
1129 ins_home(c);
1130 break;
1131
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001132 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 case K_S_END:
1135 case K_C_END:
1136 ins_end(c);
1137 break;
1138
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001139 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001140 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1141 ins_s_left();
1142 else
1143 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 break;
1145
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001146 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147 case K_C_LEFT:
1148 ins_s_left();
1149 break;
1150
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001151 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001152 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1153 ins_s_right();
1154 else
1155 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156 break;
1157
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001158 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 case K_C_RIGHT:
1160 ins_s_right();
1161 break;
1162
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001163 case K_UP: /* <Up> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001164#ifdef FEAT_INS_EXPAND
1165 if (pum_visible())
1166 goto docomplete;
1167#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001168 if (mod_mask & MOD_MASK_SHIFT)
1169 ins_pageup();
1170 else
1171 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 break;
1173
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001174 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 case K_PAGEUP:
1176 case K_KPAGEUP:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001177#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001178 if (pum_visible())
1179 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001180#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 ins_pageup();
1182 break;
1183
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001184 case K_DOWN: /* <Down> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001185#ifdef FEAT_INS_EXPAND
1186 if (pum_visible())
1187 goto docomplete;
1188#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001189 if (mod_mask & MOD_MASK_SHIFT)
1190 ins_pagedown();
1191 else
1192 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001193 break;
1194
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001195 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 case K_PAGEDOWN:
1197 case K_KPAGEDOWN:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001198#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001199 if (pum_visible())
1200 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001201#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 ins_pagedown();
1203 break;
1204
1205#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001206 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 ins_drop();
1208 break;
1209#endif
1210
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001211 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212 c = TAB;
1213 /* FALLTHROUGH */
1214
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001215 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1217 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
1218 goto docomplete;
1219#endif
1220 inserted_space = FALSE;
1221 if (ins_tab())
1222 goto normalchar; /* insert TAB as a normal char */
1223 auto_format(FALSE, TRUE);
1224 break;
1225
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001226 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 c = CAR;
1228 /* FALLTHROUGH */
1229 case CAR:
1230 case NL:
1231#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
1232 /* In a quickfix window a <CR> jumps to the error under the
1233 * cursor. */
1234 if (bt_quickfix(curbuf) && c == CAR)
1235 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001236 if (curwin->w_llist_ref == NULL) /* quickfix window */
1237 do_cmdline_cmd((char_u *)".cc");
1238 else /* location list window */
1239 do_cmdline_cmd((char_u *)".ll");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 break;
1241 }
1242#endif
1243#ifdef FEAT_CMDWIN
1244 if (cmdwin_type != 0)
1245 {
1246 /* Execute the command in the cmdline window. */
1247 cmdwin_result = CAR;
1248 goto doESCkey;
1249 }
1250#endif
1251 if (ins_eol(c) && !p_im)
1252 goto doESCkey; /* out of memory */
1253 auto_format(FALSE, FALSE);
1254 inserted_space = FALSE;
1255 break;
1256
1257#if defined(FEAT_DIGRAPHS) || defined (FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001258 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259# ifdef FEAT_INS_EXPAND
1260 if (ctrl_x_mode == CTRL_X_DICTIONARY)
1261 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001262 if (has_compl_option(TRUE))
1263 goto docomplete;
1264 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 }
1266# endif
1267# ifdef FEAT_DIGRAPHS
1268 c = ins_digraph();
1269 if (c == NUL)
1270 break;
1271# endif
1272 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001273#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274
1275#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001276 case Ctrl_X: /* Enter CTRL-X mode */
1277 ins_ctrl_x();
1278 break;
1279
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001280 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 if (ctrl_x_mode != CTRL_X_TAGS)
1282 goto normalchar;
1283 goto docomplete;
1284
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001285 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 if (ctrl_x_mode != CTRL_X_FILES)
1287 goto normalchar;
1288 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001289
1290 case 's': /* Spelling completion after ^X */
1291 case Ctrl_S:
1292 if (ctrl_x_mode != CTRL_X_SPELL)
1293 goto normalchar;
1294 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295#endif
1296
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001297 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298#ifdef FEAT_INS_EXPAND
1299 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
1300#endif
1301 {
1302 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1303 if (p_im)
1304 {
1305 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1306 break;
1307 goto doESCkey;
1308 }
1309 goto normalchar;
1310 }
1311#ifdef FEAT_INS_EXPAND
1312 /* FALLTHROUGH */
1313
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001314 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 case Ctrl_N:
1316 /* if 'complete' is empty then plain ^P is no longer special,
1317 * but it is under other ^X modes */
1318 if (*curbuf->b_p_cpt == NUL
1319 && ctrl_x_mode != 0
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001320 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 goto normalchar;
1322
1323docomplete:
1324 if (ins_complete(c) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001325 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326 break;
1327#endif /* FEAT_INS_EXPAND */
1328
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001329 case Ctrl_Y: /* copy from previous line or scroll down */
1330 case Ctrl_E: /* copy from next line or scroll up */
1331 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 break;
1333
1334 default:
1335#ifdef UNIX
1336 if (c == intr_char) /* special interrupt char */
1337 goto do_intr;
1338#endif
1339
1340 /*
1341 * Insert a nomal character.
1342 */
1343normalchar:
1344#ifdef FEAT_SMARTINDENT
1345 /* Try to perform smart-indenting. */
1346 ins_try_si(c);
1347#endif
1348
1349 if (c == ' ')
1350 {
1351 inserted_space = TRUE;
1352#ifdef FEAT_CINDENT
1353 if (inindent(0))
1354 can_cindent = FALSE;
1355#endif
1356 if (Insstart_blank_vcol == MAXCOL
1357 && curwin->w_cursor.lnum == Insstart.lnum)
1358 Insstart_blank_vcol = get_nolist_virtcol();
1359 }
1360
1361 if (vim_iswordc(c) || !echeck_abbr(
1362#ifdef FEAT_MBYTE
1363 /* Add ABBR_OFF for characters above 0x100, this is
1364 * what check_abbr() expects. */
1365 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1366#endif
1367 c))
1368 {
1369 insert_special(c, FALSE, FALSE);
1370#ifdef FEAT_RIGHTLEFT
1371 revins_legal++;
1372 revins_chars++;
1373#endif
1374 }
1375
1376 auto_format(FALSE, TRUE);
1377
1378#ifdef FEAT_FOLDING
1379 /* When inserting a character the cursor line must never be in a
1380 * closed fold. */
1381 foldOpenCursor();
1382#endif
1383 break;
1384 } /* end of switch (c) */
1385
1386 /* If the cursor was moved we didn't just insert a space */
1387 if (arrow_used)
1388 inserted_space = FALSE;
1389
1390#ifdef FEAT_CINDENT
1391 if (can_cindent && cindent_on()
1392# ifdef FEAT_INS_EXPAND
1393 && ctrl_x_mode == 0
1394# endif
1395 )
1396 {
1397force_cindent:
1398 /*
1399 * Indent now if a key was typed that is in 'cinkeys'.
1400 */
1401 if (in_cinkeys(c, ' ', line_is_white))
1402 {
1403 if (stop_arrow() == OK)
1404 /* re-indent the current line */
1405 do_c_expr_indent();
1406 }
1407 }
1408#endif /* FEAT_CINDENT */
1409
1410 } /* for (;;) */
1411 /* NOTREACHED */
1412}
1413
1414/*
1415 * Redraw for Insert mode.
1416 * This is postponed until getting the next character to make '$' in the 'cpo'
1417 * option work correctly.
1418 * Only redraw when there are no characters available. This speeds up
1419 * inserting sequences of characters (e.g., for CTRL-R).
1420 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001421/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001422 static void
Bram Moolenaar754b5602006-02-09 23:53:20 +00001423ins_redraw(ready)
1424 int ready; /* not busy with something */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425{
1426 if (!char_avail())
1427 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00001428#ifdef FEAT_AUTOCMD
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001429 /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
1430 * visible, the command might delete it. */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001431 if (ready && has_cursormovedI()
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001432 && !equalpos(last_cursormoved, curwin->w_cursor)
1433# ifdef FEAT_INS_EXPAND
1434 && !pum_visible()
1435# endif
1436 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00001437 {
1438 apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, FALSE, curbuf);
1439 last_cursormoved = curwin->w_cursor;
1440 }
1441#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001442 if (must_redraw)
1443 update_screen(0);
1444 else if (clear_cmdline || redraw_cmdline)
1445 showmode(); /* clear cmdline and show mode */
1446 showruler(FALSE);
1447 setcursor();
1448 emsg_on_display = FALSE; /* may remove error message now */
1449 }
1450}
1451
1452/*
1453 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1454 */
1455 static void
1456ins_ctrl_v()
1457{
1458 int c;
1459
1460 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001461 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462
1463 if (redrawing() && !char_avail())
1464 edit_putchar('^', TRUE);
1465 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1466
1467#ifdef FEAT_CMDL_INFO
1468 add_to_showcmd_c(Ctrl_V);
1469#endif
1470
1471 c = get_literal();
1472#ifdef FEAT_CMDL_INFO
1473 clear_showcmd();
1474#endif
1475 insert_special(c, FALSE, TRUE);
1476#ifdef FEAT_RIGHTLEFT
1477 revins_chars++;
1478 revins_legal++;
1479#endif
1480}
1481
1482/*
1483 * Put a character directly onto the screen. It's not stored in a buffer.
1484 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1485 */
1486static int pc_status;
1487#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1488#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1489#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1490#define PC_STATUS_SET 3 /* pc_bytes was filled */
1491#ifdef FEAT_MBYTE
1492static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1493#else
1494static char_u pc_bytes[2]; /* saved bytes */
1495#endif
1496static int pc_attr;
1497static int pc_row;
1498static int pc_col;
1499
1500 void
1501edit_putchar(c, highlight)
1502 int c;
1503 int highlight;
1504{
1505 int attr;
1506
1507 if (ScreenLines != NULL)
1508 {
1509 update_topline(); /* just in case w_topline isn't valid */
1510 validate_cursor();
1511 if (highlight)
1512 attr = hl_attr(HLF_8);
1513 else
1514 attr = 0;
1515 pc_row = W_WINROW(curwin) + curwin->w_wrow;
1516 pc_col = W_WINCOL(curwin);
1517#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1518 pc_status = PC_STATUS_UNSET;
1519#endif
1520#ifdef FEAT_RIGHTLEFT
1521 if (curwin->w_p_rl)
1522 {
1523 pc_col += W_WIDTH(curwin) - 1 - curwin->w_wcol;
1524# ifdef FEAT_MBYTE
1525 if (has_mbyte)
1526 {
1527 int fix_col = mb_fix_col(pc_col, pc_row);
1528
1529 if (fix_col != pc_col)
1530 {
1531 screen_putchar(' ', pc_row, fix_col, attr);
1532 --curwin->w_wcol;
1533 pc_status = PC_STATUS_RIGHT;
1534 }
1535 }
1536# endif
1537 }
1538 else
1539#endif
1540 {
1541 pc_col += curwin->w_wcol;
1542#ifdef FEAT_MBYTE
1543 if (mb_lefthalve(pc_row, pc_col))
1544 pc_status = PC_STATUS_LEFT;
1545#endif
1546 }
1547
1548 /* save the character to be able to put it back */
1549#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1550 if (pc_status == PC_STATUS_UNSET)
1551#endif
1552 {
1553 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1554 pc_status = PC_STATUS_SET;
1555 }
1556 screen_putchar(c, pc_row, pc_col, attr);
1557 }
1558}
1559
1560/*
1561 * Undo the previous edit_putchar().
1562 */
1563 void
1564edit_unputchar()
1565{
1566 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1567 {
1568#if defined(FEAT_MBYTE)
1569 if (pc_status == PC_STATUS_RIGHT)
1570 ++curwin->w_wcol;
1571 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
1572 redrawWinline(curwin->w_cursor.lnum, FALSE);
1573 else
1574#endif
1575 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1576 }
1577}
1578
1579/*
1580 * Called when p_dollar is set: display a '$' at the end of the changed text
1581 * Only works when cursor is in the line that changes.
1582 */
1583 void
1584display_dollar(col)
1585 colnr_T col;
1586{
1587 colnr_T save_col;
1588
1589 if (!redrawing())
1590 return;
1591
1592 cursor_off();
1593 save_col = curwin->w_cursor.col;
1594 curwin->w_cursor.col = col;
1595#ifdef FEAT_MBYTE
1596 if (has_mbyte)
1597 {
1598 char_u *p;
1599
1600 /* If on the last byte of a multi-byte move to the first byte. */
1601 p = ml_get_curline();
1602 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1603 }
1604#endif
1605 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
1606 if (curwin->w_wcol < W_WIDTH(curwin))
1607 {
1608 edit_putchar('$', FALSE);
1609 dollar_vcol = curwin->w_virtcol;
1610 }
1611 curwin->w_cursor.col = save_col;
1612}
1613
1614/*
1615 * Call this function before moving the cursor from the normal insert position
1616 * in insert mode.
1617 */
1618 static void
1619undisplay_dollar()
1620{
1621 if (dollar_vcol)
1622 {
1623 dollar_vcol = 0;
1624 redrawWinline(curwin->w_cursor.lnum, FALSE);
1625 }
1626}
1627
1628/*
1629 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1630 * Keep the cursor on the same character.
1631 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1632 * type == INDENT_DEC decrease indent (for CTRL-D)
1633 * type == INDENT_SET set indent to "amount"
1634 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1635 */
1636 void
1637change_indent(type, amount, round, replaced)
1638 int type;
1639 int amount;
1640 int round;
1641 int replaced; /* replaced character, put on replace stack */
1642{
1643 int vcol;
1644 int last_vcol;
1645 int insstart_less; /* reduction for Insstart.col */
1646 int new_cursor_col;
1647 int i;
1648 char_u *ptr;
1649 int save_p_list;
1650 int start_col;
1651 colnr_T vc;
1652#ifdef FEAT_VREPLACE
1653 colnr_T orig_col = 0; /* init for GCC */
1654 char_u *new_line, *orig_line = NULL; /* init for GCC */
1655
1656 /* VREPLACE mode needs to know what the line was like before changing */
1657 if (State & VREPLACE_FLAG)
1658 {
1659 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1660 orig_col = curwin->w_cursor.col;
1661 }
1662#endif
1663
1664 /* for the following tricks we don't want list mode */
1665 save_p_list = curwin->w_p_list;
1666 curwin->w_p_list = FALSE;
1667 vc = getvcol_nolist(&curwin->w_cursor);
1668 vcol = vc;
1669
1670 /*
1671 * For Replace mode we need to fix the replace stack later, which is only
1672 * possible when the cursor is in the indent. Remember the number of
1673 * characters before the cursor if it's possible.
1674 */
1675 start_col = curwin->w_cursor.col;
1676
1677 /* determine offset from first non-blank */
1678 new_cursor_col = curwin->w_cursor.col;
1679 beginline(BL_WHITE);
1680 new_cursor_col -= curwin->w_cursor.col;
1681
1682 insstart_less = curwin->w_cursor.col;
1683
1684 /*
1685 * If the cursor is in the indent, compute how many screen columns the
1686 * cursor is to the left of the first non-blank.
1687 */
1688 if (new_cursor_col < 0)
1689 vcol = get_indent() - vcol;
1690
1691 if (new_cursor_col > 0) /* can't fix replace stack */
1692 start_col = -1;
1693
1694 /*
1695 * Set the new indent. The cursor will be put on the first non-blank.
1696 */
1697 if (type == INDENT_SET)
1698 (void)set_indent(amount, SIN_CHANGED);
1699 else
1700 {
1701#ifdef FEAT_VREPLACE
1702 int save_State = State;
1703
1704 /* Avoid being called recursively. */
1705 if (State & VREPLACE_FLAG)
1706 State = INSERT;
1707#endif
1708 shift_line(type == INDENT_DEC, round, 1);
1709#ifdef FEAT_VREPLACE
1710 State = save_State;
1711#endif
1712 }
1713 insstart_less -= curwin->w_cursor.col;
1714
1715 /*
1716 * Try to put cursor on same character.
1717 * If the cursor is at or after the first non-blank in the line,
1718 * compute the cursor column relative to the column of the first
1719 * non-blank character.
1720 * If we are not in insert mode, leave the cursor on the first non-blank.
1721 * If the cursor is before the first non-blank, position it relative
1722 * to the first non-blank, counted in screen columns.
1723 */
1724 if (new_cursor_col >= 0)
1725 {
1726 /*
1727 * When changing the indent while the cursor is touching it, reset
1728 * Insstart_col to 0.
1729 */
1730 if (new_cursor_col == 0)
1731 insstart_less = MAXCOL;
1732 new_cursor_col += curwin->w_cursor.col;
1733 }
1734 else if (!(State & INSERT))
1735 new_cursor_col = curwin->w_cursor.col;
1736 else
1737 {
1738 /*
1739 * Compute the screen column where the cursor should be.
1740 */
1741 vcol = get_indent() - vcol;
1742 curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
1743
1744 /*
1745 * Advance the cursor until we reach the right screen column.
1746 */
1747 vcol = last_vcol = 0;
1748 new_cursor_col = -1;
1749 ptr = ml_get_curline();
1750 while (vcol <= (int)curwin->w_virtcol)
1751 {
1752 last_vcol = vcol;
1753#ifdef FEAT_MBYTE
1754 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001755 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 else
1757#endif
1758 ++new_cursor_col;
1759 vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
1760 }
1761 vcol = last_vcol;
1762
1763 /*
1764 * May need to insert spaces to be able to position the cursor on
1765 * the right screen column.
1766 */
1767 if (vcol != (int)curwin->w_virtcol)
1768 {
1769 curwin->w_cursor.col = new_cursor_col;
1770 i = (int)curwin->w_virtcol - vcol;
1771 ptr = alloc(i + 1);
1772 if (ptr != NULL)
1773 {
1774 new_cursor_col += i;
1775 ptr[i] = NUL;
1776 while (--i >= 0)
1777 ptr[i] = ' ';
1778 ins_str(ptr);
1779 vim_free(ptr);
1780 }
1781 }
1782
1783 /*
1784 * When changing the indent while the cursor is in it, reset
1785 * Insstart_col to 0.
1786 */
1787 insstart_less = MAXCOL;
1788 }
1789
1790 curwin->w_p_list = save_p_list;
1791
1792 if (new_cursor_col <= 0)
1793 curwin->w_cursor.col = 0;
1794 else
1795 curwin->w_cursor.col = new_cursor_col;
1796 curwin->w_set_curswant = TRUE;
1797 changed_cline_bef_curs();
1798
1799 /*
1800 * May have to adjust the start of the insert.
1801 */
1802 if (State & INSERT)
1803 {
1804 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1805 {
1806 if ((int)Insstart.col <= insstart_less)
1807 Insstart.col = 0;
1808 else
1809 Insstart.col -= insstart_less;
1810 }
1811 if ((int)ai_col <= insstart_less)
1812 ai_col = 0;
1813 else
1814 ai_col -= insstart_less;
1815 }
1816
1817 /*
1818 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1819 * If the number of characters before the cursor decreased, need to pop a
1820 * few characters from the replace stack.
1821 * If the number of characters before the cursor increased, need to push a
1822 * few NULs onto the replace stack.
1823 */
1824 if (REPLACE_NORMAL(State) && start_col >= 0)
1825 {
1826 while (start_col > (int)curwin->w_cursor.col)
1827 {
1828 replace_join(0); /* remove a NUL from the replace stack */
1829 --start_col;
1830 }
1831 while (start_col < (int)curwin->w_cursor.col || replaced)
1832 {
1833 replace_push(NUL);
1834 if (replaced)
1835 {
1836 replace_push(replaced);
1837 replaced = NUL;
1838 }
1839 ++start_col;
1840 }
1841 }
1842
1843#ifdef FEAT_VREPLACE
1844 /*
1845 * For VREPLACE mode, we also have to fix the replace stack. In this case
1846 * it is always possible because we backspace over the whole line and then
1847 * put it back again the way we wanted it.
1848 */
1849 if (State & VREPLACE_FLAG)
1850 {
1851 /* If orig_line didn't allocate, just return. At least we did the job,
1852 * even if you can't backspace. */
1853 if (orig_line == NULL)
1854 return;
1855
1856 /* Save new line */
1857 new_line = vim_strsave(ml_get_curline());
1858 if (new_line == NULL)
1859 return;
1860
1861 /* We only put back the new line up to the cursor */
1862 new_line[curwin->w_cursor.col] = NUL;
1863
1864 /* Put back original line */
1865 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1866 curwin->w_cursor.col = orig_col;
1867
1868 /* Backspace from cursor to start of line */
1869 backspace_until_column(0);
1870
1871 /* Insert new stuff into line again */
1872 ins_bytes(new_line);
1873
1874 vim_free(new_line);
1875 }
1876#endif
1877}
1878
1879/*
1880 * Truncate the space at the end of a line. This is to be used only in an
1881 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1882 * modes.
1883 */
1884 void
1885truncate_spaces(line)
1886 char_u *line;
1887{
1888 int i;
1889
1890 /* find start of trailing white space */
1891 for (i = (int)STRLEN(line) - 1; i >= 0 && vim_iswhite(line[i]); i--)
1892 {
1893 if (State & REPLACE_FLAG)
1894 replace_join(0); /* remove a NUL from the replace stack */
1895 }
1896 line[i + 1] = NUL;
1897}
1898
1899#if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \
1900 || defined(FEAT_COMMENTS) || defined(PROTO)
1901/*
1902 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1903 * modes correctly. May also be used when not in insert mode at all.
1904 */
1905 void
1906backspace_until_column(col)
1907 int col;
1908{
1909 while ((int)curwin->w_cursor.col > col)
1910 {
1911 curwin->w_cursor.col--;
1912 if (State & REPLACE_FLAG)
1913 replace_do_bs();
1914 else
1915 (void)del_char(FALSE);
1916 }
1917}
1918#endif
1919
1920#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1921/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001922 * CTRL-X pressed in Insert mode.
1923 */
1924 static void
1925ins_ctrl_x()
1926{
1927 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1928 * CTRL-V works like CTRL-N */
1929 if (ctrl_x_mode != CTRL_X_CMDLINE)
1930 {
1931 /* if the next ^X<> won't ADD nothing, then reset
1932 * compl_cont_status */
1933 if (compl_cont_status & CONT_N_ADDS)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001934 compl_cont_status |= CONT_INTRPT;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001935 else
1936 compl_cont_status = 0;
1937 /* We're not sure which CTRL-X mode it will be yet */
1938 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1939 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1940 edit_submode_pre = NULL;
1941 showmode();
1942 }
1943}
1944
1945/*
1946 * Return TRUE if the 'dict' or 'tsr' option can be used.
1947 */
1948 static int
1949has_compl_option(dict_opt)
1950 int dict_opt;
1951{
Bram Moolenaar0b238792006-03-02 22:49:12 +00001952 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00001953# ifdef FEAT_SPELL
1954 && !curwin->w_p_spell
1955# endif
1956 )
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001957 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
1958 {
1959 ctrl_x_mode = 0;
1960 edit_submode = NULL;
1961 msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
1962 : (char_u *)_("'thesaurus' option is empty"),
1963 hl_attr(HLF_E));
1964 if (emsg_silent == 0)
1965 {
1966 vim_beep();
1967 setcursor();
1968 out_flush();
1969 ui_delay(2000L, FALSE);
1970 }
1971 return FALSE;
1972 }
1973 return TRUE;
1974}
1975
1976/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
1978 * This depends on the current mode.
1979 */
1980 int
1981vim_is_ctrl_x_key(c)
1982 int c;
1983{
1984 /* Always allow ^R - let it's results then be checked */
1985 if (c == Ctrl_R)
1986 return TRUE;
1987
Bram Moolenaare3226be2005-12-18 22:10:00 +00001988 /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001989 if (ins_compl_pum_key(c))
Bram Moolenaare3226be2005-12-18 22:10:00 +00001990 return TRUE;
1991
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 switch (ctrl_x_mode)
1993 {
1994 case 0: /* Not in any CTRL-X mode */
1995 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
1996 case CTRL_X_NOT_DEFINED_YET:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001997 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1999 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
2000 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
Bram Moolenaar488c6512005-08-11 20:09:58 +00002001 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
2002 || c == Ctrl_S || c == 's');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003 case CTRL_X_SCROLL:
2004 return (c == Ctrl_Y || c == Ctrl_E);
2005 case CTRL_X_WHOLE_LINE:
2006 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
2007 case CTRL_X_FILES:
2008 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
2009 case CTRL_X_DICTIONARY:
2010 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
2011 case CTRL_X_THESAURUS:
2012 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
2013 case CTRL_X_TAGS:
2014 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
2015#ifdef FEAT_FIND_ID
2016 case CTRL_X_PATH_PATTERNS:
2017 return (c == Ctrl_P || c == Ctrl_N);
2018 case CTRL_X_PATH_DEFINES:
2019 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
2020#endif
2021 case CTRL_X_CMDLINE:
2022 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
2023 || c == Ctrl_X);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002024#ifdef FEAT_COMPL_FUNC
2025 case CTRL_X_FUNCTION:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002026 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002027 case CTRL_X_OMNI:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002028 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002029#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002030 case CTRL_X_SPELL:
2031 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 }
2033 EMSG(_(e_internal));
2034 return FALSE;
2035}
2036
2037/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002038 * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 * case of the originally typed text is used, and the case of the completed
2040 * text is infered, ie this tries to work out what case you probably wanted
2041 * the rest of the word to be in -- webb
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002042 * TODO: make this work for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 */
2044 int
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002045ins_compl_add_infercase(str, len, icase, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046 char_u *str;
2047 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002048 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 char_u *fname;
2050 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002051 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052{
2053 int has_lower = FALSE;
2054 int was_letter = FALSE;
2055 int idx;
2056
2057 if (p_ic && curbuf->b_p_inf && len < IOSIZE)
2058 {
2059 /* Infer case of completed part -- webb */
2060 /* Use IObuff, str would change text in buffer! */
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002061 vim_strncpy(IObuff, str, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062
2063 /* Rule 1: Were any chars converted to lower? */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002064 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002066 if (islower(compl_orig_text[idx]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067 {
2068 has_lower = TRUE;
2069 if (isupper(IObuff[idx]))
2070 {
2071 /* Rule 1 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002072 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073 IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
2074 break;
2075 }
2076 }
2077 }
2078
2079 /*
2080 * Rule 2: No lower case, 2nd consecutive letter converted to
2081 * upper case.
2082 */
2083 if (!has_lower)
2084 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002085 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002087 if (was_letter && isupper(compl_orig_text[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 && islower(IObuff[idx]))
2089 {
2090 /* Rule 2 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002091 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
2093 break;
2094 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002095 was_letter = isalpha(compl_orig_text[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 }
2097 }
2098
2099 /* Copy the original case of the part we typed */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002100 STRNCPY(IObuff, compl_orig_text, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002102 return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
2103 flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 }
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002105 return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106}
2107
2108/*
2109 * Add a match to the list of matches.
2110 * If the given string is already in the list of completions, then return
Bram Moolenaar572cb562005-08-05 21:35:02 +00002111 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002112 * maybe because alloc() returns NULL, then FAIL is returned.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002114 static int
2115ins_compl_add(str, len, icase, fname, cptext, cdir, flags, dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 char_u *str;
2117 int len;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002118 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119 char_u *fname;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002120 char_u **cptext; /* extra text for popup menu or NULL */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002121 int cdir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002122 int flags;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002123 int dup; /* accept duplicate match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002125 compl_T *match;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002126 int dir = (cdir == 0 ? compl_direction : cdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127
2128 ui_breakcheck();
2129 if (got_int)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002130 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 if (len < 0)
2132 len = (int)STRLEN(str);
2133
2134 /*
2135 * If the same match is already present, don't add it.
2136 */
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002137 if (compl_first_match != NULL && !dup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002139 match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 do
2141 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002142 if ( !(match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002143 && ins_compl_equal(match, str, len)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002144 && match->cp_str[len] == NUL)
2145 return NOTDONE;
2146 match = match->cp_next;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002147 } while (match != NULL && match != compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 }
2149
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002150 /* Remove any popup menu before changing the list of matches. */
2151 ins_compl_del_pum();
2152
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153 /*
2154 * Allocate a new match structure.
2155 * Copy the values to the new match structure.
2156 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002157 match = (compl_T *)alloc_clear((unsigned)sizeof(compl_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158 if (match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002159 return FAIL;
2160 match->cp_number = -1;
2161 if (flags & ORIGINAL_TEXT)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002162 match->cp_number = 0;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002163 if ((match->cp_str = vim_strnsave(str, len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164 {
2165 vim_free(match);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002166 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002168 match->cp_icase = icase;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002169
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 /* match-fname is:
Bram Moolenaar572cb562005-08-05 21:35:02 +00002171 * - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
2173 * - NULL otherwise. --Acevedo */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002174 if (fname != NULL
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002175 && compl_curr_match != NULL
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002176 && compl_curr_match->cp_fname != NULL
2177 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002178 match->cp_fname = compl_curr_match->cp_fname;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002179 else if (fname != NULL)
2180 {
2181 match->cp_fname = vim_strsave(fname);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002182 flags |= FREE_FNAME;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 else
Bram Moolenaar572cb562005-08-05 21:35:02 +00002185 match->cp_fname = NULL;
2186 match->cp_flags = flags;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002187
2188 if (cptext != NULL)
2189 {
2190 int i;
2191
2192 for (i = 0; i < CPT_COUNT; ++i)
2193 if (cptext[i] != NULL && *cptext[i] != NUL)
2194 match->cp_text[i] = vim_strsave(cptext[i]);
2195 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002196
2197 /*
2198 * Link the new match structure in the list of matches.
2199 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002200 if (compl_first_match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002201 match->cp_next = match->cp_prev = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 else if (dir == FORWARD)
2203 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002204 match->cp_next = compl_curr_match->cp_next;
2205 match->cp_prev = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 }
2207 else /* BACKWARD */
2208 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002209 match->cp_next = compl_curr_match;
2210 match->cp_prev = compl_curr_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002212 if (match->cp_next)
2213 match->cp_next->cp_prev = match;
2214 if (match->cp_prev)
2215 match->cp_prev->cp_next = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216 else /* if there's nothing before, it is the first match */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002217 compl_first_match = match;
2218 compl_curr_match = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002219
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002220 /*
2221 * Find the longest common string if still doing that.
2222 */
2223 if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
2224 ins_compl_longest_match(match);
2225
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 return OK;
2227}
2228
2229/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002230 * Return TRUE if "str[len]" matches with match->cp_str, considering
2231 * match->cp_icase.
2232 */
2233 static int
2234ins_compl_equal(match, str, len)
2235 compl_T *match;
2236 char_u *str;
2237 int len;
2238{
2239 if (match->cp_icase)
2240 return STRNICMP(match->cp_str, str, (size_t)len) == 0;
2241 return STRNCMP(match->cp_str, str, (size_t)len) == 0;
2242}
2243
2244/*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002245 * Reduce the longest common string for match "match".
2246 */
2247 static void
2248ins_compl_longest_match(match)
2249 compl_T *match;
2250{
2251 char_u *p, *s;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002252 int c1, c2;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002253 int had_match;
2254
2255 if (compl_leader == NULL)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002256 {
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002257 /* First match, use it as a whole. */
2258 compl_leader = vim_strsave(match->cp_str);
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002259 if (compl_leader != NULL)
2260 {
2261 had_match = (curwin->w_cursor.col > compl_col);
2262 ins_compl_delete();
2263 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2264 ins_redraw(FALSE);
2265
2266 /* When the match isn't there (to avoid matching itself) remove it
2267 * again after redrawing. */
2268 if (!had_match)
2269 ins_compl_delete();
2270 compl_used_match = FALSE;
2271 }
2272 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002273 else
2274 {
2275 /* Reduce the text if this match differs from compl_leader. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002276 p = compl_leader;
2277 s = match->cp_str;
2278 while (*p != NUL)
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002279 {
2280#ifdef FEAT_MBYTE
2281 if (has_mbyte)
2282 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002283 c1 = mb_ptr2char(p);
2284 c2 = mb_ptr2char(s);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002285 }
2286 else
2287#endif
2288 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002289 c1 = *p;
2290 c2 = *s;
2291 }
2292 if (match->cp_icase ? (MB_TOLOWER(c1) != MB_TOLOWER(c2))
2293 : (c1 != c2))
2294 break;
2295#ifdef FEAT_MBYTE
2296 if (has_mbyte)
2297 {
2298 mb_ptr_adv(p);
2299 mb_ptr_adv(s);
2300 }
2301 else
2302#endif
2303 {
2304 ++p;
2305 ++s;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002306 }
2307 }
2308
2309 if (*p != NUL)
2310 {
2311 /* Leader was shortened, need to change the inserted text. */
2312 *p = NUL;
2313 had_match = (curwin->w_cursor.col > compl_col);
2314 ins_compl_delete();
2315 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
2316 ins_redraw(FALSE);
2317
2318 /* When the match isn't there (to avoid matching itself) remove it
2319 * again after redrawing. */
2320 if (!had_match)
2321 ins_compl_delete();
2322 }
2323
2324 compl_used_match = FALSE;
2325 }
2326}
2327
2328/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 * Add an array of matches to the list of matches.
2330 * Frees matches[].
2331 */
2332 static void
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002333ins_compl_add_matches(num_matches, matches, icase)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334 int num_matches;
2335 char_u **matches;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002336 int icase;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337{
2338 int i;
2339 int add_r = OK;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002340 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341
Bram Moolenaar572cb562005-08-05 21:35:02 +00002342 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002343 if ((add_r = ins_compl_add(matches[i], -1, icase,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002344 NULL, NULL, dir, 0, FALSE)) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 /* if dir was BACKWARD then honor it just once */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002346 dir = FORWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347 FreeWild(num_matches, matches);
2348}
2349
2350/* Make the completion list cyclic.
2351 * Return the number of matches (excluding the original).
2352 */
2353 static int
2354ins_compl_make_cyclic()
2355{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002356 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 int count = 0;
2358
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002359 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 {
2361 /*
2362 * Find the end of the list.
2363 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002364 match = compl_first_match;
2365 /* there's always an entry for the compl_orig_text, it doesn't count. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002366 while (match->cp_next != NULL && match->cp_next != compl_first_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002368 match = match->cp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 ++count;
2370 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002371 match->cp_next = compl_first_match;
2372 compl_first_match->cp_prev = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 }
2374 return count;
2375}
2376
Bram Moolenaara94bc432006-03-10 21:42:59 +00002377/*
2378 * Start completion for the complete() function.
2379 * "startcol" is where the matched text starts (1 is first column).
2380 * "list" is the list of matches.
2381 */
2382 void
2383set_completion(startcol, list)
2384 int startcol;
2385 list_T *list;
2386{
2387 /* If already doing completions stop it. */
2388 if (ctrl_x_mode != 0)
2389 ins_compl_prep(' ');
2390 ins_compl_clear();
2391
2392 if (stop_arrow() == FAIL)
2393 return;
2394
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002395 if (startcol > (int)curwin->w_cursor.col)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002396 startcol = curwin->w_cursor.col;
2397 compl_col = startcol;
2398 compl_length = curwin->w_cursor.col - startcol;
2399 /* compl_pattern doesn't need to be set */
2400 compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
2401 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00002402 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaara94bc432006-03-10 21:42:59 +00002403 return;
2404
2405 /* Handle like dictionary completion. */
2406 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2407
2408 ins_compl_add_list(list);
2409 compl_matches = ins_compl_make_cyclic();
2410 compl_started = TRUE;
2411 compl_used_match = TRUE;
2412
2413 compl_curr_match = compl_first_match;
2414 ins_complete(Ctrl_N);
2415 out_flush();
2416}
2417
2418
Bram Moolenaar9372a112005-12-06 19:59:18 +00002419/* "compl_match_array" points the currently displayed list of entries in the
2420 * popup menu. It is NULL when there is no popup menu. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002421static pumitem_T *compl_match_array = NULL;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002422static int compl_match_arraysize;
2423
2424/*
2425 * Update the screen and when there is any scrolling remove the popup menu.
2426 */
2427 static void
2428ins_compl_upd_pum()
2429{
2430 int h;
2431
2432 if (compl_match_array != NULL)
2433 {
2434 h = curwin->w_cline_height;
2435 update_screen(0);
2436 if (h != curwin->w_cline_height)
2437 ins_compl_del_pum();
2438 }
2439}
2440
2441/*
2442 * Remove any popup menu.
2443 */
2444 static void
2445ins_compl_del_pum()
2446{
2447 if (compl_match_array != NULL)
2448 {
2449 pum_undisplay();
2450 vim_free(compl_match_array);
2451 compl_match_array = NULL;
2452 }
2453}
2454
2455/*
2456 * Return TRUE if the popup menu should be displayed.
2457 */
2458 static int
2459pum_wanted()
2460{
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002461 /* 'completeopt' must contain "menu" or "menuone" */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00002462 if (vim_strchr(p_cot, 'm') == NULL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002463 return FALSE;
2464
2465 /* The display looks bad on a B&W display. */
2466 if (t_colors < 8
2467#ifdef FEAT_GUI
2468 && !gui.in_use
2469#endif
2470 )
2471 return FALSE;
Bram Moolenaara6557602006-02-04 22:43:20 +00002472 return TRUE;
2473}
2474
2475/*
2476 * Return TRUE if there are two or more matches to be shown in the popup menu.
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002477 * One if 'completopt' contains "menuone".
Bram Moolenaara6557602006-02-04 22:43:20 +00002478 */
2479 static int
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002480pum_enough_matches()
Bram Moolenaara6557602006-02-04 22:43:20 +00002481{
2482 compl_T *compl;
2483 int i;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002484
2485 /* Don't display the popup menu if there are no matches or there is only
2486 * one (ignoring the original text). */
2487 compl = compl_first_match;
2488 i = 0;
2489 do
2490 {
2491 if (compl == NULL
2492 || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
2493 break;
2494 compl = compl->cp_next;
2495 } while (compl != compl_first_match);
2496
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002497 if (strstr((char *)p_cot, "menuone") != NULL)
2498 return (i >= 1);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002499 return (i >= 2);
2500}
2501
2502/*
2503 * Show the popup menu for the list of matches.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002504 * Also adjusts "compl_shown_match" to an entry that is actually displayed.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002505 */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002506 void
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002507ins_compl_show_pum()
2508{
2509 compl_T *compl;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002510 compl_T *shown_compl = NULL;
2511 int did_find_shown_match = FALSE;
2512 int shown_match_ok = FALSE;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002513 int i;
2514 int cur = -1;
2515 colnr_T col;
Bram Moolenaara6557602006-02-04 22:43:20 +00002516 int lead_len = 0;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002517
Bram Moolenaar65c923a2006-03-03 22:56:30 +00002518 if (!pum_wanted() || !pum_enough_matches())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002519 return;
2520
Bram Moolenaar433f7c82006-03-21 21:29:36 +00002521#if defined(FEAT_EVAL)
2522 /* Dirty hard-coded hack: remove any matchparen highlighting. */
2523 do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|3match none|endif");
2524#endif
2525
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002526 /* Update the screen before drawing the popup menu over it. */
2527 update_screen(0);
2528
2529 if (compl_match_array == NULL)
2530 {
2531 /* Need to build the popup menu list. */
2532 compl_match_arraysize = 0;
2533 compl = compl_first_match;
Bram Moolenaara6557602006-02-04 22:43:20 +00002534 if (compl_leader != NULL)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002535 lead_len = (int)STRLEN(compl_leader);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002536 do
2537 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002538 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2539 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002540 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002541 ++compl_match_arraysize;
2542 compl = compl->cp_next;
2543 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaara6557602006-02-04 22:43:20 +00002544 if (compl_match_arraysize == 0)
2545 return;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002546 compl_match_array = (pumitem_T *)alloc_clear(
2547 (unsigned)(sizeof(pumitem_T)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002548 * compl_match_arraysize));
2549 if (compl_match_array != NULL)
2550 {
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002551 /* If the current match is the original text don't find the first
2552 * match after it, don't highlight anything. */
2553 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
2554 shown_match_ok = TRUE;
2555
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002556 i = 0;
2557 compl = compl_first_match;
2558 do
2559 {
Bram Moolenaara6557602006-02-04 22:43:20 +00002560 if ((compl->cp_flags & ORIGINAL_TEXT) == 0
2561 && (compl_leader == NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002562 || ins_compl_equal(compl, compl_leader, lead_len)))
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002563 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002564 if (!shown_match_ok)
2565 {
2566 if (compl == compl_shown_match || did_find_shown_match)
2567 {
2568 /* This item is the shown match or this is the
2569 * first displayed item after the shown match. */
2570 compl_shown_match = compl;
2571 did_find_shown_match = TRUE;
2572 shown_match_ok = TRUE;
2573 }
2574 else
2575 /* Remember this displayed match for when the
2576 * shown match is just below it. */
2577 shown_compl = compl;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002578 cur = i;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002579 }
Bram Moolenaar39f05632006-03-19 22:15:26 +00002580
2581 if (compl->cp_text[CPT_ABBR] != NULL)
2582 compl_match_array[i].pum_text =
2583 compl->cp_text[CPT_ABBR];
2584 else
2585 compl_match_array[i].pum_text = compl->cp_str;
2586 compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
2587 compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
2588 if (compl->cp_text[CPT_MENU] != NULL)
2589 compl_match_array[i++].pum_extra =
2590 compl->cp_text[CPT_MENU];
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002591 else
2592 compl_match_array[i++].pum_extra = compl->cp_fname;
2593 }
2594
2595 if (compl == compl_shown_match)
2596 {
2597 did_find_shown_match = TRUE;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002598
2599 /* When the original text is the shown match don't set
2600 * compl_shown_match. */
2601 if (compl->cp_flags & ORIGINAL_TEXT)
2602 shown_match_ok = TRUE;
2603
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002604 if (!shown_match_ok && shown_compl != NULL)
2605 {
2606 /* The shown match isn't displayed, set it to the
2607 * previously displayed match. */
2608 compl_shown_match = shown_compl;
2609 shown_match_ok = TRUE;
2610 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002611 }
2612 compl = compl->cp_next;
2613 } while (compl != NULL && compl != compl_first_match);
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002614
2615 if (!shown_match_ok) /* no displayed match at all */
2616 cur = -1;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002617 }
2618 }
2619 else
2620 {
2621 /* popup menu already exists, only need to find the current item.*/
Bram Moolenaara6557602006-02-04 22:43:20 +00002622 for (i = 0; i < compl_match_arraysize; ++i)
Bram Moolenaar39f05632006-03-19 22:15:26 +00002623 if (compl_match_array[i].pum_text == compl_shown_match->cp_str
2624 || compl_match_array[i].pum_text
2625 == compl_shown_match->cp_text[CPT_ABBR])
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002626 {
2627 cur = i;
Bram Moolenaara6557602006-02-04 22:43:20 +00002628 break;
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00002629 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002630 }
2631
2632 if (compl_match_array != NULL)
2633 {
2634 /* Compute the screen column of the start of the completed text.
2635 * Use the cursor to get all wrapping and other settings right. */
2636 col = curwin->w_cursor.col;
2637 curwin->w_cursor.col = compl_col;
Bram Moolenaard289f132006-03-11 21:30:53 +00002638 pum_display(compl_match_array, compl_match_arraysize, cur);
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002639 curwin->w_cursor.col = col;
2640 }
2641}
2642
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643#define DICT_FIRST (1) /* use just first element in "dict" */
2644#define DICT_EXACT (2) /* "dict" is the exact name of a file */
Bram Moolenaar280f1262006-01-30 00:14:18 +00002645
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646/*
Bram Moolenaar0b238792006-03-02 22:49:12 +00002647 * Add any identifiers that match the given pattern in the list of dictionary
2648 * files "dict_start" to the list of completions.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 */
2650 static void
Bram Moolenaar0b238792006-03-02 22:49:12 +00002651ins_compl_dictionaries(dict_start, pat, flags, thesaurus)
2652 char_u *dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 char_u *pat;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002654 int flags; /* DICT_FIRST and/or DICT_EXACT */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002655 int thesaurus; /* Thesaurus completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656{
Bram Moolenaar0b238792006-03-02 22:49:12 +00002657 char_u *dict = dict_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 char_u *ptr;
2659 char_u *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660 regmatch_T regmatch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 char_u **files;
2662 int count;
2663 int i;
2664 int save_p_scs;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002665 int dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666
Bram Moolenaar0b238792006-03-02 22:49:12 +00002667 if (*dict == NUL)
2668 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002669#ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002670 /* When 'dictionary' is empty and spell checking is enabled use
2671 * "spell". */
2672 if (!thesaurus && curwin->w_p_spell)
2673 dict = (char_u *)"spell";
2674 else
2675#endif
2676 return;
2677 }
2678
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 buf = alloc(LSIZE);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002680 if (buf == NULL)
2681 return;
2682
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683 /* If 'infercase' is set, don't use 'smartcase' here */
2684 save_p_scs = p_scs;
2685 if (curbuf->b_p_inf)
2686 p_scs = FALSE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002687
2688 /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
2689 * to only match at the start of a line. Otherwise just match the
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002690 * pattern. Also need to double backslashes. */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002691 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2692 {
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002693 char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
2694
2695 if (pat_esc == NULL)
2696 return ;
2697 i = (int)STRLEN(pat_esc) + 10;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002698 ptr = alloc(i);
2699 if (ptr == NULL)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002700 {
2701 vim_free(pat_esc);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002702 return;
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00002703 }
2704 vim_snprintf((char *)ptr, i, "^\\s*\\zs\\V%s", pat_esc);
2705 regmatch.regprog = vim_regcomp(ptr, RE_MAGIC);
2706 vim_free(pat_esc);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002707 vim_free(ptr);
2708 }
2709 else
Bram Moolenaar0b238792006-03-02 22:49:12 +00002710 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002711 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002712 if (regmatch.regprog == NULL)
2713 goto theend;
2714 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002715
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2717 regmatch.rm_ic = ignorecase(pat);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002718 while (*dict != NUL && !got_int && !compl_interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719 {
2720 /* copy one dictionary file name into buf */
2721 if (flags == DICT_EXACT)
2722 {
2723 count = 1;
2724 files = &dict;
2725 }
2726 else
2727 {
2728 /* Expand wildcards in the dictionary name, but do not allow
2729 * backticks (for security, the 'dict' option may have been set in
2730 * a modeline). */
2731 copy_option_part(&dict, buf, LSIZE, ",");
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002732# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002733 if (!thesaurus && STRCMP(buf, "spell") == 0)
2734 count = -1;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002735 else
2736# endif
2737 if (vim_strchr(buf, '`') != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738 || expand_wildcards(1, &buf, &count, &files,
2739 EW_FILE|EW_SILENT) != OK)
2740 count = 0;
2741 }
2742
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002743# ifdef FEAT_SPELL
Bram Moolenaar0b238792006-03-02 22:49:12 +00002744 if (count == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 {
Bram Moolenaar87b5ca52006-03-04 21:55:31 +00002746 /* Complete from active spelling. Skip "\<" in the pattern, we
2747 * don't use it as a RE. */
Bram Moolenaar0b238792006-03-02 22:49:12 +00002748 if (pat[0] == '\\' && pat[1] == '<')
2749 ptr = pat + 2;
2750 else
2751 ptr = pat;
2752 spell_dump_compl(curbuf, ptr, regmatch.rm_ic, &dir, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002754 else
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002755# endif
Bram Moolenaar0b238792006-03-02 22:49:12 +00002756 {
2757 ins_compl_files(count, files, thesaurus, flags,
2758 &regmatch, buf, &dir);
2759 if (flags != DICT_EXACT)
2760 FreeWild(count, files);
2761 }
2762 if (flags != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763 break;
2764 }
Bram Moolenaar0b238792006-03-02 22:49:12 +00002765
2766theend:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 p_scs = save_p_scs;
2768 vim_free(regmatch.regprog);
2769 vim_free(buf);
2770}
2771
Bram Moolenaar0b238792006-03-02 22:49:12 +00002772 static void
2773ins_compl_files(count, files, thesaurus, flags, regmatch, buf, dir)
2774 int count;
2775 char_u **files;
2776 int thesaurus;
2777 int flags;
2778 regmatch_T *regmatch;
2779 char_u *buf;
2780 int *dir;
2781{
2782 char_u *ptr;
2783 int i;
2784 FILE *fp;
2785 int add_r;
2786
2787 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
2788 {
2789 fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
2790 if (flags != DICT_EXACT)
2791 {
2792 vim_snprintf((char *)IObuff, IOSIZE,
2793 _("Scanning dictionary: %s"), (char *)files[i]);
2794 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2795 }
2796
2797 if (fp != NULL)
2798 {
2799 /*
2800 * Read dictionary file line by line.
2801 * Check each line for a match.
2802 */
2803 while (!got_int && !compl_interrupted
2804 && !vim_fgets(buf, LSIZE, fp))
2805 {
2806 ptr = buf;
2807 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
2808 {
2809 ptr = regmatch->startp[0];
2810 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2811 ptr = find_line_end(ptr);
2812 else
2813 ptr = find_word_end(ptr);
2814 add_r = ins_compl_add_infercase(regmatch->startp[0],
2815 (int)(ptr - regmatch->startp[0]),
Bram Moolenaar91170f82006-05-05 21:15:17 +00002816 FALSE, files[i], *dir, 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002817 if (thesaurus)
2818 {
2819 char_u *wstart;
2820
2821 /*
2822 * Add the other matches on the line
2823 */
2824 while (!got_int)
2825 {
2826 /* Find start of the next word. Skip white
2827 * space and punctuation. */
2828 ptr = find_word_start(ptr);
2829 if (*ptr == NUL || *ptr == NL)
2830 break;
2831 wstart = ptr;
2832
2833 /* Find end of the word and add it. */
2834#ifdef FEAT_MBYTE
2835 if (has_mbyte)
2836 /* Japanese words may have characters in
2837 * different classes, only separate words
2838 * with single-byte non-word characters. */
2839 while (*ptr != NUL)
2840 {
2841 int l = (*mb_ptr2len)(ptr);
2842
2843 if (l < 2 && !vim_iswordc(*ptr))
2844 break;
2845 ptr += l;
2846 }
2847 else
2848#endif
2849 ptr = find_word_end(ptr);
2850 add_r = ins_compl_add_infercase(wstart,
2851 (int)(ptr - wstart),
Bram Moolenaar91170f82006-05-05 21:15:17 +00002852 FALSE, files[i], *dir, 0);
Bram Moolenaar0b238792006-03-02 22:49:12 +00002853 }
2854 }
2855 if (add_r == OK)
2856 /* if dir was BACKWARD then honor it just once */
2857 *dir = FORWARD;
2858 else if (add_r == FAIL)
2859 break;
2860 /* avoid expensive call to vim_regexec() when at end
2861 * of line */
2862 if (*ptr == '\n' || got_int)
2863 break;
2864 }
2865 line_breakcheck();
2866 ins_compl_check_keys(50);
2867 }
2868 fclose(fp);
2869 }
2870 }
2871}
2872
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873/*
2874 * Find the start of the next word.
2875 * Returns a pointer to the first char of the word. Also stops at a NUL.
2876 */
2877 char_u *
2878find_word_start(ptr)
2879 char_u *ptr;
2880{
2881#ifdef FEAT_MBYTE
2882 if (has_mbyte)
2883 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002884 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885 else
2886#endif
2887 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2888 ++ptr;
2889 return ptr;
2890}
2891
2892/*
2893 * Find the end of the word. Assumes it starts inside a word.
2894 * Returns a pointer to just after the word.
2895 */
2896 char_u *
2897find_word_end(ptr)
2898 char_u *ptr;
2899{
2900#ifdef FEAT_MBYTE
2901 int start_class;
2902
2903 if (has_mbyte)
2904 {
2905 start_class = mb_get_class(ptr);
2906 if (start_class > 1)
2907 while (*ptr != NUL)
2908 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002909 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 if (mb_get_class(ptr) != start_class)
2911 break;
2912 }
2913 }
2914 else
2915#endif
2916 while (vim_iswordc(*ptr))
2917 ++ptr;
2918 return ptr;
2919}
2920
2921/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002922 * Find the end of the line, omitting CR and NL at the end.
2923 * Returns a pointer to just after the line.
2924 */
2925 static char_u *
2926find_line_end(ptr)
2927 char_u *ptr;
2928{
2929 char_u *s;
2930
2931 s = ptr + STRLEN(ptr);
2932 while (s > ptr && (s[-1] == CAR || s[-1] == NL))
2933 --s;
2934 return s;
2935}
2936
2937/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 * Free the list of completions
2939 */
2940 static void
2941ins_compl_free()
2942{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002943 compl_T *match;
Bram Moolenaar39f05632006-03-19 22:15:26 +00002944 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002946 vim_free(compl_pattern);
2947 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002948 vim_free(compl_leader);
2949 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002951 if (compl_first_match == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002953
2954 ins_compl_del_pum();
2955 pum_clear();
2956
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002957 compl_curr_match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 do
2959 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002960 match = compl_curr_match;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002961 compl_curr_match = compl_curr_match->cp_next;
2962 vim_free(match->cp_str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 /* several entries may use the same fname, free it just once. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002964 if (match->cp_flags & FREE_FNAME)
2965 vim_free(match->cp_fname);
Bram Moolenaar39f05632006-03-19 22:15:26 +00002966 for (i = 0; i < CPT_COUNT; ++i)
2967 vim_free(match->cp_text[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968 vim_free(match);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002969 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
2970 compl_first_match = compl_curr_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971}
2972
2973 static void
2974ins_compl_clear()
2975{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002976 compl_cont_status = 0;
2977 compl_started = FALSE;
2978 compl_matches = 0;
2979 vim_free(compl_pattern);
2980 compl_pattern = NULL;
Bram Moolenaara6557602006-02-04 22:43:20 +00002981 vim_free(compl_leader);
2982 compl_leader = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 edit_submode_extra = NULL;
Bram Moolenaara94bc432006-03-10 21:42:59 +00002984 vim_free(compl_orig_text);
2985 compl_orig_text = NULL;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00002986 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987}
2988
2989/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002990 * Return TRUE when Insert completion is active.
2991 */
2992 int
2993ins_compl_active()
2994{
2995 return compl_started;
2996}
2997
2998/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002999 * Delete one character before the cursor and show the subset of the matches
3000 * that match the word that is now before the cursor.
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003001 * Returns the character to be used, NUL if the work is done and another char
3002 * to be got from the user.
Bram Moolenaara6557602006-02-04 22:43:20 +00003003 */
3004 static int
3005ins_compl_bs()
3006{
3007 char_u *line;
3008 char_u *p;
3009
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003010 line = ml_get_curline();
3011 p = line + curwin->w_cursor.col;
3012 mb_ptr_back(line, p);
3013
3014 /* Stop completion when the whole word was deleted. */
3015 if ((int)(p - line) - (int)compl_col <= 0)
3016 return K_BS;
3017
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003018 /* For redo we need to repeat this backspace. */
3019 AppendCharToRedobuff(K_BS);
3020
3021 /* Deleted more than what was used to find matches or didn't finish
3022 * finding all matches: need to look for matches all over again. */
3023 if (curwin->w_cursor.col <= compl_col + compl_length
3024 || compl_was_interrupted)
3025 ins_compl_restart();
Bram Moolenaara6557602006-02-04 22:43:20 +00003026
Bram Moolenaara6557602006-02-04 22:43:20 +00003027 vim_free(compl_leader);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003028 compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
Bram Moolenaara6557602006-02-04 22:43:20 +00003029 if (compl_leader != NULL)
3030 {
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003031 ins_compl_new_leader();
3032 return NUL;
3033 }
3034 return K_BS;
3035}
Bram Moolenaara6557602006-02-04 22:43:20 +00003036
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003037/*
3038 * Called after changing "compl_leader".
3039 * Show the popup menu with a different set of matches.
3040 * May also search for matches again if the previous search was interrupted.
3041 */
3042 static void
3043ins_compl_new_leader()
3044{
3045 ins_compl_del_pum();
3046 ins_compl_delete();
3047 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3048 compl_used_match = FALSE;
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003049
3050 if (compl_started)
3051 ins_compl_set_original_text(compl_leader);
3052 else
3053 {
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00003054#ifdef FEAT_SPELL
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003055 spell_bad_len = 0; /* need to redetect bad word */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00003056#endif
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003057 /*
3058 * Matches were cleared, need to search for them now. First display
3059 * the changed text before the cursor. Set "compl_restarting" to
3060 * avoid that the first match is inserted.
3061 */
3062 update_screen(0);
3063#ifdef FEAT_GUI
3064 if (gui.in_use)
3065 {
3066 /* Show the cursor after the match, not after the redrawn text. */
3067 setcursor();
3068 out_flush();
3069 gui_update_cursor(FALSE, FALSE);
Bram Moolenaara6557602006-02-04 22:43:20 +00003070 }
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003071#endif
3072 compl_restarting = TRUE;
3073 if (ins_complete(Ctrl_N) == FAIL)
3074 compl_cont_status = 0;
3075 compl_restarting = FALSE;
3076 }
Bram Moolenaara6557602006-02-04 22:43:20 +00003077
Bram Moolenaar0440ca32006-05-13 13:24:33 +00003078#if 0 /* disabled, made CTRL-L, BS and typing char jump to original text. */
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003079 if (!compl_used_match)
3080 {
Bram Moolenaar9e54a0e2006-04-14 20:42:25 +00003081 /* Go to the original text, since none of the matches is inserted. */
3082 if (compl_first_match->cp_prev != NULL
3083 && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT))
3084 compl_shown_match = compl_first_match->cp_prev;
3085 else
3086 compl_shown_match = compl_first_match;
3087 compl_curr_match = compl_shown_match;
3088 compl_shows_dir = compl_direction;
Bram Moolenaara6557602006-02-04 22:43:20 +00003089 }
Bram Moolenaar0440ca32006-05-13 13:24:33 +00003090#endif
3091 compl_enter_selects = !compl_used_match;
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003092
3093 /* Show the popup menu with a different set of matches. */
3094 ins_compl_show_pum();
Bram Moolenaara6557602006-02-04 22:43:20 +00003095}
3096
3097/*
3098 * Append one character to the match leader. May reduce the number of
3099 * matches.
3100 */
3101 static void
3102ins_compl_addleader(c)
3103 int c;
3104{
3105#ifdef FEAT_MBYTE
3106 int cc;
3107
3108 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
3109 {
3110 char_u buf[MB_MAXBYTES + 1];
3111
3112 (*mb_char2bytes)(c, buf);
3113 buf[cc] = NUL;
3114 ins_char_bytes(buf, cc);
3115 }
3116 else
3117#endif
3118 ins_char(c);
3119
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003120 /* For redo we need to count this character so that the number of
3121 * backspaces is correct. */
3122 AppendCharToRedobuff(c);
3123
3124 /* If we didn't complete finding matches we must search again. */
3125 if (compl_was_interrupted)
3126 ins_compl_restart();
3127
Bram Moolenaara6557602006-02-04 22:43:20 +00003128 vim_free(compl_leader);
3129 compl_leader = vim_strnsave(ml_get_curline() + compl_col,
3130 curwin->w_cursor.col - compl_col);
3131 if (compl_leader != NULL)
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00003132 ins_compl_new_leader();
3133}
3134
3135/*
3136 * Setup for finding completions again without leaving CTRL-X mode. Used when
3137 * BS or a key was typed while still searching for matches.
3138 */
3139 static void
3140ins_compl_restart()
3141{
3142 ins_compl_free();
3143 compl_started = FALSE;
3144 compl_matches = 0;
3145 compl_cont_status = 0;
3146 compl_cont_mode = 0;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003147}
3148
3149/*
3150 * Set the first match, the original text.
3151 */
3152 static void
3153ins_compl_set_original_text(str)
3154 char_u *str;
3155{
3156 char_u *p;
3157
3158 /* Replace the original text entry. */
3159 if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */
3160 {
3161 p = vim_strsave(str);
3162 if (p != NULL)
3163 {
3164 vim_free(compl_first_match->cp_str);
3165 compl_first_match->cp_str = p;
3166 }
Bram Moolenaara6557602006-02-04 22:43:20 +00003167 }
3168}
3169
3170/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003171 * Append one character to the match leader. May reduce the number of
3172 * matches.
3173 */
3174 static void
3175ins_compl_addfrommatch()
3176{
3177 char_u *p;
3178 int len = curwin->w_cursor.col - compl_col;
3179 int c;
Bram Moolenaar0440ca32006-05-13 13:24:33 +00003180 compl_T *cp;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003181
3182 p = compl_shown_match->cp_str;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00003183 if ((int)STRLEN(p) <= len) /* the match is too short */
Bram Moolenaar0440ca32006-05-13 13:24:33 +00003184 {
3185 /* When still at the original match use the first entry that matches
3186 * the leader. */
3187 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
3188 {
3189 p = NULL;
3190 for (cp = compl_shown_match->cp_next; cp != NULL
3191 && cp != compl_first_match; cp = cp->cp_next)
3192 {
3193 if (ins_compl_equal(cp, compl_leader,
3194 (int)STRLEN(compl_leader)))
3195 {
3196 p = cp->cp_str;
3197 break;
3198 }
3199 }
3200 if (p == NULL || (int)STRLEN(p) <= len)
3201 return;
3202 }
3203 else
3204 return;
3205 }
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003206 p += len;
3207#ifdef FEAT_MBYTE
3208 c = mb_ptr2char(p);
3209#else
3210 c = *p;
3211#endif
3212 ins_compl_addleader(c);
3213}
3214
3215/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 * Prepare for Insert mode completion, or stop it.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003217 * Called just after typing a character in Insert mode.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003218 * Returns TRUE when the character is not to be inserted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003220 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221ins_compl_prep(c)
3222 int c;
3223{
3224 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 int temp;
3226 int want_cindent;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003227 int retval = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228
3229 /* Forget any previous 'special' messages if this is actually
3230 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
3231 */
3232 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
3233 edit_submode_extra = NULL;
3234
3235 /* Ignore end of Select mode mapping */
3236 if (c == K_SELECT)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003237 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003239 /* Set "compl_get_longest" when finding the first matches. */
3240 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
3241 || (ctrl_x_mode == 0 && !compl_started))
3242 {
3243 compl_get_longest = (vim_strchr(p_cot, 'l') != NULL);
3244 compl_used_match = TRUE;
3245 }
3246
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
3248 {
3249 /*
3250 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
3251 * it will be yet. Now we decide.
3252 */
3253 switch (c)
3254 {
3255 case Ctrl_E:
3256 case Ctrl_Y:
3257 ctrl_x_mode = CTRL_X_SCROLL;
3258 if (!(State & REPLACE_FLAG))
3259 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
3260 else
3261 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
3262 edit_submode_pre = NULL;
3263 showmode();
3264 break;
3265 case Ctrl_L:
3266 ctrl_x_mode = CTRL_X_WHOLE_LINE;
3267 break;
3268 case Ctrl_F:
3269 ctrl_x_mode = CTRL_X_FILES;
3270 break;
3271 case Ctrl_K:
3272 ctrl_x_mode = CTRL_X_DICTIONARY;
3273 break;
3274 case Ctrl_R:
3275 /* Simply allow ^R to happen without affecting ^X mode */
3276 break;
3277 case Ctrl_T:
3278 ctrl_x_mode = CTRL_X_THESAURUS;
3279 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003280#ifdef FEAT_COMPL_FUNC
3281 case Ctrl_U:
3282 ctrl_x_mode = CTRL_X_FUNCTION;
3283 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003284 case Ctrl_O:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003285 ctrl_x_mode = CTRL_X_OMNI;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003286 break;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003287#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003288 case 's':
3289 case Ctrl_S:
3290 ctrl_x_mode = CTRL_X_SPELL;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003291#ifdef FEAT_SPELL
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003292 ++emsg_off; /* Avoid getting the E756 error twice. */
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003293 spell_back_to_badword();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003294 --emsg_off;
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003295#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00003296 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297 case Ctrl_RSB:
3298 ctrl_x_mode = CTRL_X_TAGS;
3299 break;
3300#ifdef FEAT_FIND_ID
3301 case Ctrl_I:
3302 case K_S_TAB:
3303 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
3304 break;
3305 case Ctrl_D:
3306 ctrl_x_mode = CTRL_X_PATH_DEFINES;
3307 break;
3308#endif
3309 case Ctrl_V:
3310 case Ctrl_Q:
3311 ctrl_x_mode = CTRL_X_CMDLINE;
3312 break;
3313 case Ctrl_P:
3314 case Ctrl_N:
3315 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
3316 * just started ^X mode, or there were enough ^X's to cancel
3317 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
3318 * do normal expansion when interrupting a different mode (say
3319 * ^X^F^X^P or ^P^X^X^P, see below)
3320 * nothing changes if interrupting mode 0, (eg, the flag
3321 * doesn't change when going to ADDING mode -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003322 if (!(compl_cont_status & CONT_INTRPT))
3323 compl_cont_status |= CONT_LOCAL;
3324 else if (compl_cont_mode != 0)
3325 compl_cont_status &= ~CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 /* FALLTHROUGH */
3327 default:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003328 /* If we have typed at least 2 ^X's... for modes != 0, we set
3329 * compl_cont_status = 0 (eg, as if we had just started ^X
3330 * mode).
3331 * For mode 0, we set "compl_cont_mode" to an impossible
3332 * value, in both cases ^X^X can be used to restart the same
3333 * mode (avoiding ADDING mode).
3334 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
3335 * 'complete' and local ^P expansions respectively.
3336 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
3337 * mode -- Acevedo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 if (c == Ctrl_X)
3339 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003340 if (compl_cont_mode != 0)
3341 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003343 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 }
3345 ctrl_x_mode = 0;
3346 edit_submode = NULL;
3347 showmode();
3348 break;
3349 }
3350 }
3351 else if (ctrl_x_mode != 0)
3352 {
3353 /* We're already in CTRL-X mode, do we stay in it? */
3354 if (!vim_is_ctrl_x_key(c))
3355 {
3356 if (ctrl_x_mode == CTRL_X_SCROLL)
3357 ctrl_x_mode = 0;
3358 else
3359 ctrl_x_mode = CTRL_X_FINISHED;
3360 edit_submode = NULL;
3361 }
3362 showmode();
3363 }
3364
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003365 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366 {
3367 /* Show error message from attempted keyword completion (probably
3368 * 'Pattern not found') until another key is hit, then go back to
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003369 * showing what mode we are in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 showmode();
Bram Moolenaard12f5c12006-01-25 22:10:52 +00003371 if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R
3372 && !ins_compl_pum_key(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 || ctrl_x_mode == CTRL_X_FINISHED)
3374 {
3375 /* Get here when we have finished typing a sequence of ^N and
3376 * ^P or other completion characters in CTRL-X mode. Free up
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003377 * memory that was used, and make sure we can redo the insert. */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003378 if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003380 char_u *p;
3381
Bram Moolenaar071d4272004-06-13 20:20:40 +00003382 /*
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003383 * If any of the original typed text has been changed, eg when
3384 * ignorecase is set, we must add back-spaces to the redo
3385 * buffer. We add as few as necessary to delete just the part
3386 * of the original text that has changed.
3387 * When using the longest match, edited the match or used
3388 * CTRL-E then don't use the current match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389 */
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003390 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
3391 ptr = compl_curr_match->cp_str;
3392 else if (compl_leader != NULL)
3393 ptr = compl_leader;
3394 else
3395 ptr = compl_orig_text;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003396 p = compl_orig_text;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003397 for (temp = 0; p[temp] != NUL && p[temp] == ptr[temp]; ++temp)
3398 ;
3399#ifdef FEAT_MBYTE
3400 if (temp > 0)
3401 temp -= (*mb_head_off)(compl_orig_text, p + temp);
3402#endif
3403 for (p += temp; *p != NUL; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404 AppendCharToRedobuff(K_BS);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00003405 AppendToRedobuffLit(ptr + temp, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 }
3407
3408#ifdef FEAT_CINDENT
3409 want_cindent = (can_cindent && cindent_on());
3410#endif
3411 /*
3412 * When completing whole lines: fix indent for 'cindent'.
3413 * Otherwise, break line if it's too long.
3414 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003415 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 {
3417#ifdef FEAT_CINDENT
3418 /* re-indent the current line */
3419 if (want_cindent)
3420 {
3421 do_c_expr_indent();
3422 want_cindent = FALSE; /* don't do it again */
3423 }
3424#endif
3425 }
3426 else
3427 {
3428 /* put the cursor on the last char, for 'tw' formatting */
3429 curwin->w_cursor.col--;
3430 if (stop_arrow() == OK)
3431 insertchar(NUL, 0, -1);
3432 curwin->w_cursor.col++;
3433 }
3434
3435 auto_format(FALSE, TRUE);
3436
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003437 /* If the popup menu is displayed pressing CTRL-Y means accepting
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003438 * the selection without inserting anything. When
3439 * compl_enter_selects is set the Enter key does the same. */
3440 if ((c == Ctrl_Y || (compl_enter_selects
3441 && (c == CAR || c == K_KENTER || c == NL)))
3442 && pum_visible())
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003443 retval = TRUE;
3444
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003445 /* CTRL-E means completion is Ended, go back to the typed text. */
3446 if (c == Ctrl_E)
3447 {
3448 ins_compl_delete();
3449 if (compl_leader != NULL)
3450 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
3451 else if (compl_first_match != NULL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003452 ins_bytes(compl_orig_text
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00003453 + curwin->w_cursor.col - compl_col);
3454 retval = TRUE;
3455 }
3456
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 ins_compl_free();
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003458 compl_started = FALSE;
3459 compl_matches = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 msg_clr_cmdline(); /* necessary for "noshowmode" */
3461 ctrl_x_mode = 0;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003462 compl_enter_selects = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 if (edit_submode != NULL)
3464 {
3465 edit_submode = NULL;
3466 showmode();
3467 }
3468
3469#ifdef FEAT_CINDENT
3470 /*
3471 * Indent now if a key was typed that is in 'cinkeys'.
3472 */
3473 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
3474 do_c_expr_indent();
3475#endif
3476 }
3477 }
3478
3479 /* reset continue_* if we left expansion-mode, if we stay they'll be
3480 * (re)set properly in ins_complete() */
3481 if (!vim_is_ctrl_x_key(c))
3482 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003483 compl_cont_status = 0;
3484 compl_cont_mode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003485 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003486
3487 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488}
3489
3490/*
3491 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
3492 * (depending on flag) starting from buf and looking for a non-scanned
3493 * buffer (other than curbuf). curbuf is special, if it is called with
3494 * buf=curbuf then it has to be the first call for a given flag/expansion.
3495 *
3496 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
3497 */
3498 static buf_T *
3499ins_compl_next_buf(buf, flag)
3500 buf_T *buf;
3501 int flag;
3502{
3503#ifdef FEAT_WINDOWS
3504 static win_T *wp;
3505#endif
3506
3507 if (flag == 'w') /* just windows */
3508 {
3509#ifdef FEAT_WINDOWS
3510 if (buf == curbuf) /* first call for this flag/expansion */
3511 wp = curwin;
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003512 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513 && wp->w_buffer->b_scanned)
3514 ;
3515 buf = wp->w_buffer;
3516#else
3517 buf = curbuf;
3518#endif
3519 }
3520 else
3521 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
3522 * (unlisted buffers)
3523 * When completing whole lines skip unloaded buffers. */
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00003524 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 && ((flag == 'U'
3526 ? buf->b_p_bl
3527 : (!buf->b_p_bl
3528 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003529 || buf->b_scanned))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 ;
3531 return buf;
3532}
3533
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003534#ifdef FEAT_COMPL_FUNC
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003535static void expand_by_function __ARGS((int type, char_u *base));
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003536
3537/*
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003538 * Execute user defined complete function 'completefunc' or 'omnifunc', and
Bram Moolenaare344bea2005-09-01 20:46:49 +00003539 * get matches in "matches".
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003540 */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003541 static void
3542expand_by_function(type, base)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003543 int type; /* CTRL_X_OMNI or CTRL_X_FUNCTION */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003544 char_u *base;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003545{
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003546 list_T *matchlist;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003547 char_u *args[2];
Bram Moolenaare344bea2005-09-01 20:46:49 +00003548 char_u *funcname;
3549 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003550
Bram Moolenaare344bea2005-09-01 20:46:49 +00003551 funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
3552 if (*funcname == NUL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003553 return;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003554
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003555 /* Call 'completefunc' to obtain the list of matches. */
3556 args[0] = (char_u *)"0";
Bram Moolenaare344bea2005-09-01 20:46:49 +00003557 args[1] = base;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003558
Bram Moolenaare344bea2005-09-01 20:46:49 +00003559 pos = curwin->w_cursor;
3560 matchlist = call_func_retlist(funcname, 2, args, FALSE);
3561 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003562 if (matchlist == NULL)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003563 return;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003564
Bram Moolenaara94bc432006-03-10 21:42:59 +00003565 ins_compl_add_list(matchlist);
3566 list_unref(matchlist);
3567}
3568#endif /* FEAT_COMPL_FUNC */
3569
Bram Moolenaar39f05632006-03-19 22:15:26 +00003570#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00003571/*
3572 * Add completions from a list.
Bram Moolenaara94bc432006-03-10 21:42:59 +00003573 */
3574 static void
3575ins_compl_add_list(list)
3576 list_T *list;
3577{
3578 listitem_T *li;
Bram Moolenaara94bc432006-03-10 21:42:59 +00003579 int dir = compl_direction;
3580
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003581 /* Go through the List with matches and add each of them. */
Bram Moolenaara94bc432006-03-10 21:42:59 +00003582 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003583 {
Bram Moolenaar39f05632006-03-19 22:15:26 +00003584 if (ins_compl_add_tv(&li->li_tv, dir) == OK)
3585 /* if dir was BACKWARD then honor it just once */
3586 dir = FORWARD;
Bram Moolenaar280f1262006-01-30 00:14:18 +00003587 else if (did_emsg)
3588 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003589 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003590}
Bram Moolenaar39f05632006-03-19 22:15:26 +00003591
3592/*
3593 * Add a match to the list of matches from a typeval_T.
3594 * If the given string is already in the list of completions, then return
3595 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
3596 * maybe because alloc() returns NULL, then FAIL is returned.
3597 */
3598 int
3599ins_compl_add_tv(tv, dir)
3600 typval_T *tv;
3601 int dir;
3602{
3603 char_u *word;
Bram Moolenaar91170f82006-05-05 21:15:17 +00003604 int icase = FALSE;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003605 int dup = FALSE;
Bram Moolenaar39f05632006-03-19 22:15:26 +00003606 char_u *(cptext[CPT_COUNT]);
3607
3608 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
3609 {
3610 word = get_dict_string(tv->vval.v_dict, (char_u *)"word", FALSE);
3611 cptext[CPT_ABBR] = get_dict_string(tv->vval.v_dict,
3612 (char_u *)"abbr", FALSE);
3613 cptext[CPT_MENU] = get_dict_string(tv->vval.v_dict,
3614 (char_u *)"menu", FALSE);
3615 cptext[CPT_KIND] = get_dict_string(tv->vval.v_dict,
3616 (char_u *)"kind", FALSE);
3617 cptext[CPT_INFO] = get_dict_string(tv->vval.v_dict,
3618 (char_u *)"info", FALSE);
3619 if (get_dict_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL)
3620 icase = get_dict_number(tv->vval.v_dict, (char_u *)"icase");
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003621 if (get_dict_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
3622 dup = get_dict_number(tv->vval.v_dict, (char_u *)"dup");
Bram Moolenaar39f05632006-03-19 22:15:26 +00003623 }
3624 else
3625 {
3626 word = get_tv_string_chk(tv);
3627 vim_memset(cptext, 0, sizeof(cptext));
3628 }
3629 if (word == NULL || *word == NUL)
3630 return FAIL;
Bram Moolenaar4a85b412006-04-23 22:40:29 +00003631 return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, dup);
Bram Moolenaar39f05632006-03-19 22:15:26 +00003632}
Bram Moolenaara94bc432006-03-10 21:42:59 +00003633#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003634
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003635/*
3636 * Get the next expansion(s), using "compl_pattern".
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003637 * The search starts at position "ini" in curbuf and in the direction
3638 * compl_direction.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003639 * When "compl_started" is FALSE start at that position, otherwise continue
3640 * where we stopped searching before.
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003641 * This may return before finding all the matches.
3642 * Return the total number of matches or -1 if still unknown -- Acevedo
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 */
3644 static int
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003645ins_compl_get_exp(ini)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 pos_T *ini;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647{
3648 static pos_T first_match_pos;
3649 static pos_T last_match_pos;
3650 static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003651 static int found_all = FALSE; /* Found all matches of a
3652 certain type. */
3653 static buf_T *ins_buf = NULL; /* buffer being scanned */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654
Bram Moolenaar572cb562005-08-05 21:35:02 +00003655 pos_T *pos;
3656 char_u **matches;
3657 int save_p_scs;
3658 int save_p_ws;
3659 int save_p_ic;
3660 int i;
3661 int num_matches;
3662 int len;
3663 int found_new_match;
3664 int type = ctrl_x_mode;
3665 char_u *ptr;
3666 char_u *dict = NULL;
3667 int dict_f = 0;
3668 compl_T *old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003670 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 {
3672 for (ins_buf = firstbuf; ins_buf != NULL; ins_buf = ins_buf->b_next)
3673 ins_buf->b_scanned = 0;
3674 found_all = FALSE;
3675 ins_buf = curbuf;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003676 e_cpt = (compl_cont_status & CONT_LOCAL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003677 ? (char_u *)"." : curbuf->b_p_cpt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 last_match_pos = first_match_pos = *ini;
3679 }
3680
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003681 old_match = compl_curr_match; /* remember the last current match */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003682 pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
3684 for (;;)
3685 {
3686 found_new_match = FAIL;
3687
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003688 /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 * or if found_all says this entry is done. For ^X^L only use the
3690 * entries from 'complete' that look in loaded buffers. */
3691 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003692 && (!compl_started || found_all))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 {
3694 found_all = FALSE;
3695 while (*e_cpt == ',' || *e_cpt == ' ')
3696 e_cpt++;
3697 if (*e_cpt == '.' && !curbuf->b_scanned)
3698 {
3699 ins_buf = curbuf;
3700 first_match_pos = *ini;
3701 /* So that ^N can match word immediately after cursor */
3702 if (ctrl_x_mode == 0)
3703 dec(&first_match_pos);
3704 last_match_pos = first_match_pos;
3705 type = 0;
3706 }
3707 else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
3708 && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
3709 {
3710 /* Scan a buffer, but not the current one. */
3711 if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
3712 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003713 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 first_match_pos.col = last_match_pos.col = 0;
3715 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
3716 last_match_pos.lnum = 0;
3717 type = 0;
3718 }
3719 else /* unloaded buffer, scan like dictionary */
3720 {
3721 found_all = TRUE;
3722 if (ins_buf->b_fname == NULL)
3723 continue;
3724 type = CTRL_X_DICTIONARY;
3725 dict = ins_buf->b_fname;
3726 dict_f = DICT_EXACT;
3727 }
Bram Moolenaar555b2802005-05-19 21:08:39 +00003728 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 ins_buf->b_fname == NULL
3730 ? buf_spname(ins_buf)
3731 : ins_buf->b_sfname == NULL
3732 ? (char *)ins_buf->b_fname
3733 : (char *)ins_buf->b_sfname);
3734 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3735 }
3736 else if (*e_cpt == NUL)
3737 break;
3738 else
3739 {
3740 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3741 type = -1;
3742 else if (*e_cpt == 'k' || *e_cpt == 's')
3743 {
3744 if (*e_cpt == 'k')
3745 type = CTRL_X_DICTIONARY;
3746 else
3747 type = CTRL_X_THESAURUS;
3748 if (*++e_cpt != ',' && *e_cpt != NUL)
3749 {
3750 dict = e_cpt;
3751 dict_f = DICT_FIRST;
3752 }
3753 }
3754#ifdef FEAT_FIND_ID
3755 else if (*e_cpt == 'i')
3756 type = CTRL_X_PATH_PATTERNS;
3757 else if (*e_cpt == 'd')
3758 type = CTRL_X_PATH_DEFINES;
3759#endif
3760 else if (*e_cpt == ']' || *e_cpt == 't')
3761 {
3762 type = CTRL_X_TAGS;
3763 sprintf((char*)IObuff, _("Scanning tags."));
3764 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
3765 }
3766 else
3767 type = -1;
3768
3769 /* in any case e_cpt is advanced to the next entry */
3770 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
3771
3772 found_all = TRUE;
3773 if (type == -1)
3774 continue;
3775 }
3776 }
3777
3778 switch (type)
3779 {
3780 case -1:
3781 break;
3782#ifdef FEAT_FIND_ID
3783 case CTRL_X_PATH_PATTERNS:
3784 case CTRL_X_PATH_DEFINES:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003785 find_pattern_in_path(compl_pattern, compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003786 (int)STRLEN(compl_pattern), FALSE, FALSE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787 (type == CTRL_X_PATH_DEFINES
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003788 && !(compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
3790 (linenr_T)1, (linenr_T)MAXLNUM);
3791 break;
3792#endif
3793
3794 case CTRL_X_DICTIONARY:
3795 case CTRL_X_THESAURUS:
3796 ins_compl_dictionaries(
Bram Moolenaar0b238792006-03-02 22:49:12 +00003797 dict != NULL ? dict
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 : (type == CTRL_X_THESAURUS
3799 ? (*curbuf->b_p_tsr == NUL
3800 ? p_tsr
3801 : curbuf->b_p_tsr)
3802 : (*curbuf->b_p_dict == NUL
3803 ? p_dict
3804 : curbuf->b_p_dict)),
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003805 compl_pattern,
Bram Moolenaar0b238792006-03-02 22:49:12 +00003806 dict != NULL ? dict_f
3807 : 0, type == CTRL_X_THESAURUS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 dict = NULL;
3809 break;
3810
3811 case CTRL_X_TAGS:
3812 /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
3813 save_p_ic = p_ic;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003814 p_ic = ignorecase(compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815
3816 /* Find up to TAG_MANY matches. Avoids that an enourmous number
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003817 * of matches is found when compl_pattern is empty */
3818 if (find_tags(compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
3820 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
3821 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3822 {
Bram Moolenaar91170f82006-05-05 21:15:17 +00003823 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 }
3825 p_ic = save_p_ic;
3826 break;
3827
3828 case CTRL_X_FILES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003829 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
3831 {
3832
3833 /* May change home directory back to "~". */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003834 tilde_replace(compl_pattern, num_matches, matches);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003835 ins_compl_add_matches(num_matches, matches,
3836#ifdef CASE_INSENSITIVE_FILENAME
3837 TRUE
3838#else
3839 FALSE
3840#endif
3841 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 }
3843 break;
3844
3845 case CTRL_X_CMDLINE:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003846 if (expand_cmdline(&compl_xp, compl_pattern,
3847 (int)STRLEN(compl_pattern),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 &num_matches, &matches) == EXPAND_OK)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003849 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 break;
3851
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003852#ifdef FEAT_COMPL_FUNC
3853 case CTRL_X_FUNCTION:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003854 case CTRL_X_OMNI:
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003855 expand_by_function(type, compl_pattern);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003856 break;
3857#endif
3858
Bram Moolenaar488c6512005-08-11 20:09:58 +00003859 case CTRL_X_SPELL:
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003860#ifdef FEAT_SPELL
Bram Moolenaar488c6512005-08-11 20:09:58 +00003861 num_matches = expand_spelling(first_match_pos.lnum,
3862 first_match_pos.col, compl_pattern, &matches);
3863 if (num_matches > 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003864 ins_compl_add_matches(num_matches, matches, FALSE);
Bram Moolenaar488c6512005-08-11 20:09:58 +00003865#endif
3866 break;
3867
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 default: /* normal ^P/^N and ^X^L */
3869 /*
3870 * If 'infercase' is set, don't use 'smartcase' here
3871 */
3872 save_p_scs = p_scs;
3873 if (ins_buf->b_p_inf)
3874 p_scs = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003875
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876 /* buffers other than curbuf are scanned from the beginning or the
3877 * end but never from the middle, thus setting nowrapscan in this
3878 * buffers is a good idea, on the other hand, we always set
3879 * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
3880 save_p_ws = p_ws;
3881 if (ins_buf != curbuf)
3882 p_ws = FALSE;
3883 else if (*e_cpt == '.')
3884 p_ws = TRUE;
3885 for (;;)
3886 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003887 int flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003889 /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that
3890 * has added a word that was at the beginning of the line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003892 || (compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 found_new_match = search_for_exact_line(ins_buf, pos,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003894 compl_direction, compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 else
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00003896 found_new_match = searchit(NULL, ins_buf, pos,
3897 compl_direction,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003898 compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
Bram Moolenaara23ccb82006-02-27 00:08:02 +00003899 RE_LAST, (linenr_T)0);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003900 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003902 /* set "compl_started" even on fail */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003903 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 first_match_pos = *pos;
3905 last_match_pos = *pos;
3906 }
3907 else if (first_match_pos.lnum == last_match_pos.lnum
Bram Moolenaarc7453f52006-02-10 23:20:28 +00003908 && first_match_pos.col == last_match_pos.col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909 found_new_match = FAIL;
3910 if (found_new_match == FAIL)
3911 {
3912 if (ins_buf == curbuf)
3913 found_all = TRUE;
3914 break;
3915 }
3916
3917 /* when ADDING, the text before the cursor matches, skip it */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003918 if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 && ini->lnum == pos->lnum
3920 && ini->col == pos->col)
3921 continue;
3922 ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
3923 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3924 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003925 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 {
3927 if (pos->lnum >= ins_buf->b_ml.ml_line_count)
3928 continue;
3929 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3930 if (!p_paste)
3931 ptr = skipwhite(ptr);
3932 }
3933 len = (int)STRLEN(ptr);
3934 }
3935 else
3936 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003937 char_u *tmp_ptr = ptr;
3938
3939 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003941 tmp_ptr += compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942 /* Skip if already inside a word. */
3943 if (vim_iswordp(tmp_ptr))
3944 continue;
3945 /* Find start of next word. */
3946 tmp_ptr = find_word_start(tmp_ptr);
3947 }
3948 /* Find end of this word. */
3949 tmp_ptr = find_word_end(tmp_ptr);
3950 len = (int)(tmp_ptr - ptr);
3951
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003952 if ((compl_cont_status & CONT_ADDING)
3953 && len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 {
3955 if (pos->lnum < ins_buf->b_ml.ml_line_count)
3956 {
3957 /* Try next line, if any. the new word will be
3958 * "join" as if the normal command "J" was used.
3959 * IOSIZE is always greater than
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003960 * compl_length, so the next STRNCPY always
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 * works -- Acevedo */
3962 STRNCPY(IObuff, ptr, len);
3963 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3964 tmp_ptr = ptr = skipwhite(ptr);
3965 /* Find start of next word. */
3966 tmp_ptr = find_word_start(tmp_ptr);
3967 /* Find end of next word. */
3968 tmp_ptr = find_word_end(tmp_ptr);
3969 if (tmp_ptr > ptr)
3970 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003971 if (*ptr != ')' && IObuff[len - 1] != TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003973 if (IObuff[len - 1] != ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003974 IObuff[len++] = ' ';
3975 /* IObuf =~ "\k.* ", thus len >= 2 */
3976 if (p_js
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003977 && (IObuff[len - 2] == '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 || (vim_strchr(p_cpo, CPO_JOINSP)
3979 == NULL
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003980 && (IObuff[len - 2] == '?'
3981 || IObuff[len - 2] == '!'))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982 IObuff[len++] = ' ';
3983 }
3984 /* copy as much as posible of the new word */
3985 if (tmp_ptr - ptr >= IOSIZE - len)
3986 tmp_ptr = ptr + IOSIZE - len - 1;
3987 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3988 len += (int)(tmp_ptr - ptr);
Bram Moolenaar572cb562005-08-05 21:35:02 +00003989 flags |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 }
3991 IObuff[len] = NUL;
3992 ptr = IObuff;
3993 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003994 if (len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 continue;
3996 }
3997 }
Bram Moolenaar91170f82006-05-05 21:15:17 +00003998 if (ins_compl_add_infercase(ptr, len, FALSE,
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003999 ins_buf == curbuf ? NULL : ins_buf->b_sfname,
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00004000 0, flags) != NOTDONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001 {
4002 found_new_match = OK;
4003 break;
4004 }
4005 }
4006 p_scs = save_p_scs;
4007 p_ws = save_p_ws;
4008 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004009
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004010 /* check if compl_curr_match has changed, (e.g. other type of
4011 * expansion added somenthing) */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004012 if (type != 0 && compl_curr_match != old_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 found_new_match = OK;
4014
4015 /* break the loop for specialized modes (use 'complete' just for the
4016 * generic ctrl_x_mode == 0) or when we've found a new match */
4017 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004018 || found_new_match != FAIL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004019 {
4020 if (got_int)
4021 break;
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004022 /* Fill the popup menu as soon as possible. */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004023 if (pum_wanted() && type != -1)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004024 ins_compl_check_keys(0);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004025
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004026 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
4027 || compl_interrupted)
4028 break;
4029 compl_started = TRUE;
4030 }
4031 else
4032 {
4033 /* Mark a buffer scanned when it has been scanned completely */
4034 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
4035 ins_buf->b_scanned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004036
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004037 compl_started = FALSE;
4038 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004040 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041
4042 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
4043 && *e_cpt == NUL) /* Got to end of 'complete' */
4044 found_new_match = FAIL;
4045
4046 i = -1; /* total of matches, unknown */
4047 if (found_new_match == FAIL
4048 || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
4049 i = ins_compl_make_cyclic();
4050
4051 /* If several matches were added (FORWARD) or the search failed and has
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004052 * just been made cyclic then we have to move compl_curr_match to the next
4053 * or previous entry (if any) -- Acevedo */
Bram Moolenaara94bc432006-03-10 21:42:59 +00004054 compl_curr_match = compl_direction == FORWARD ? old_match->cp_next
4055 : old_match->cp_prev;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004056 if (compl_curr_match == NULL)
4057 compl_curr_match = old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004058 return i;
4059}
4060
4061/* Delete the old text being completed. */
4062 static void
4063ins_compl_delete()
4064{
4065 int i;
4066
4067 /*
4068 * In insert mode: Delete the typed part.
4069 * In replace mode: Put the old characters back, if any.
4070 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004071 i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 backspace_until_column(i);
4073 changed_cline_bef_curs();
4074}
4075
4076/* Insert the new text being completed. */
4077 static void
4078ins_compl_insert()
4079{
Bram Moolenaar572cb562005-08-05 21:35:02 +00004080 ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00004081 if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
4082 compl_used_match = FALSE;
4083 else
4084 compl_used_match = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085}
4086
4087/*
4088 * Fill in the next completion in the current direction.
Bram Moolenaar572cb562005-08-05 21:35:02 +00004089 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
4090 * get more completions. If it is FALSE, then we just do nothing when there
4091 * are no more completions in a given direction. The latter case is used when
4092 * we are still in the middle of finding completions, to allow browsing
4093 * through the ones found so far.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 * Return the total number of matches, or -1 if still unknown -- webb.
4095 *
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004096 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
4097 * compl_shown_match here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 *
4099 * Note that this function may be called recursively once only. First with
Bram Moolenaar572cb562005-08-05 21:35:02 +00004100 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
4101 * calls this function with "allow_get_expansion" FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 */
4103 static int
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004104ins_compl_next(allow_get_expansion, count, insert_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105 int allow_get_expansion;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004106 int count; /* repeat completion this many times; should
4107 be at least 1 */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004108 int insert_match; /* Insert the newly selected match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109{
4110 int num_matches = -1;
4111 int i;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004112 int todo = count;
Bram Moolenaara6557602006-02-04 22:43:20 +00004113 compl_T *found_compl = NULL;
4114 int found_end = FALSE;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004115 int advance;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004117 if (compl_leader != NULL
4118 && (compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 {
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004120 /* Set "compl_shown_match" to the actually shown match, it may differ
4121 * when "compl_leader" is used to omit some of the matches. */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004122 while (!ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004123 compl_leader, (int)STRLEN(compl_leader))
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004124 && compl_shown_match->cp_next != NULL
4125 && compl_shown_match->cp_next != compl_first_match)
4126 compl_shown_match = compl_shown_match->cp_next;
Bram Moolenaar0440ca32006-05-13 13:24:33 +00004127
4128 /* If we didn't find it searching forward, and compl_shows_dir is
4129 * backward, find the last match. */
4130 if (compl_shows_dir == BACKWARD
4131 && !ins_compl_equal(compl_shown_match,
4132 compl_leader, (int)STRLEN(compl_leader))
4133 && (compl_shown_match->cp_next == NULL
4134 || compl_shown_match->cp_next == compl_first_match))
4135 {
4136 while (!ins_compl_equal(compl_shown_match,
4137 compl_leader, (int)STRLEN(compl_leader))
4138 && compl_shown_match->cp_prev != NULL
4139 && compl_shown_match->cp_prev != compl_first_match)
4140 compl_shown_match = compl_shown_match->cp_prev;
4141 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004142 }
4143
4144 if (allow_get_expansion && insert_match
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00004145 && (!(compl_get_longest || compl_restarting) || compl_used_match))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 /* Delete old text to be replaced */
4147 ins_compl_delete();
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004148
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004149 /* When finding the longest common text we stick at the original text,
4150 * don't let CTRL-N or CTRL-P move to the first match. */
4151 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4152
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00004153 /* When restarting the search don't insert the first match either. */
4154 if (compl_restarting)
4155 {
4156 advance = FALSE;
4157 compl_restarting = FALSE;
4158 }
4159
Bram Moolenaare3226be2005-12-18 22:10:00 +00004160 /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4161 * around. */
4162 while (--todo >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 {
Bram Moolenaare3226be2005-12-18 22:10:00 +00004164 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004166 if (compl_pending != 0)
4167 --compl_pending;
Bram Moolenaare3226be2005-12-18 22:10:00 +00004168 compl_shown_match = compl_shown_match->cp_next;
Bram Moolenaara6557602006-02-04 22:43:20 +00004169 found_end = (compl_first_match != NULL
4170 && (compl_shown_match->cp_next == compl_first_match
4171 || compl_shown_match == compl_first_match));
Bram Moolenaare3226be2005-12-18 22:10:00 +00004172 }
4173 else if (compl_shows_dir == BACKWARD
4174 && compl_shown_match->cp_prev != NULL)
4175 {
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004176 if (compl_pending != 0)
4177 ++compl_pending;
Bram Moolenaara6557602006-02-04 22:43:20 +00004178 found_end = (compl_shown_match == compl_first_match);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004179 compl_shown_match = compl_shown_match->cp_prev;
Bram Moolenaara6557602006-02-04 22:43:20 +00004180 found_end |= (compl_shown_match == compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 }
4182 else
Bram Moolenaare3226be2005-12-18 22:10:00 +00004183 {
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004184 if (advance)
4185 {
4186 if (compl_shows_dir == BACKWARD)
4187 --compl_pending;
4188 else
4189 ++compl_pending;
4190 }
Bram Moolenaara6557602006-02-04 22:43:20 +00004191 if (!allow_get_expansion)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004192 return -1;
Bram Moolenaara6557602006-02-04 22:43:20 +00004193
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00004194 /* Find matches. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00004195 num_matches = ins_compl_get_exp(&compl_startpos);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004196 if (compl_pending != 0 && compl_direction == compl_shows_dir
4197 && advance)
Bram Moolenaara6557602006-02-04 22:43:20 +00004198 compl_shown_match = compl_curr_match;
4199 found_end = FALSE;
4200 }
4201 if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
4202 && compl_leader != NULL
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004203 && !ins_compl_equal(compl_shown_match,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004204 compl_leader, (int)STRLEN(compl_leader)))
Bram Moolenaara6557602006-02-04 22:43:20 +00004205 ++todo;
4206 else
4207 /* Remember a matching item. */
4208 found_compl = compl_shown_match;
4209
4210 /* Stop at the end of the list when we found a usable match. */
4211 if (found_end)
4212 {
4213 if (found_compl != NULL)
4214 {
4215 compl_shown_match = found_compl;
4216 break;
4217 }
4218 todo = 1; /* use first usable match after wrapping around */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 }
4221
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004222 /* Insert the text of the new completion, or the compl_leader. */
4223 if (insert_match)
4224 {
4225 if (!compl_get_longest || compl_used_match)
4226 ins_compl_insert();
4227 else
4228 ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
4229 }
4230 else
4231 compl_used_match = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232
4233 if (!allow_get_expansion)
4234 {
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004235 /* may undisplay the popup menu first */
4236 ins_compl_upd_pum();
4237
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004238 /* redraw to show the user what was inserted */
4239 update_screen(0);
4240
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004241 /* display the updated popup menu */
4242 ins_compl_show_pum();
Bram Moolenaar14716812006-05-04 21:54:08 +00004243#ifdef FEAT_GUI
4244 if (gui.in_use)
4245 {
4246 /* Show the cursor after the match, not after the redrawn text. */
4247 setcursor();
4248 out_flush();
4249 gui_update_cursor(FALSE, FALSE);
4250 }
4251#endif
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004252
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 /* Delete old text to be replaced, since we're still searching and
4254 * don't want to match ourselves! */
4255 ins_compl_delete();
4256 }
4257
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004258 /* Enter will select a match when the match wasn't inserted and the popup
4259 * menu is visislbe. */
4260 compl_enter_selects = !insert_match && compl_match_array != NULL;
4261
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 /*
4263 * Show the file name for the match (if any)
4264 * Truncate the file name to avoid a wait for return.
4265 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004266 if (compl_shown_match->cp_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 {
4268 STRCPY(IObuff, "match in file ");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004269 i = (vim_strsize(compl_shown_match->cp_fname) + 16) - sc_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 if (i <= 0)
4271 i = 0;
4272 else
4273 STRCAT(IObuff, "<");
Bram Moolenaar572cb562005-08-05 21:35:02 +00004274 STRCAT(IObuff, compl_shown_match->cp_fname + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275 msg(IObuff);
4276 redraw_cmdline = FALSE; /* don't overwrite! */
4277 }
4278
4279 return num_matches;
4280}
4281
4282/*
4283 * Call this while finding completions, to check whether the user has hit a key
4284 * that should change the currently displayed completion, or exit completion
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004285 * mode. Also, when compl_pending is not zero, show a completion as soon as
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 * possible. -- webb
Bram Moolenaar572cb562005-08-05 21:35:02 +00004287 * "frequency" specifies out of how many calls we actually check.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 */
4289 void
Bram Moolenaar572cb562005-08-05 21:35:02 +00004290ins_compl_check_keys(frequency)
4291 int frequency;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292{
4293 static int count = 0;
4294
4295 int c;
4296
4297 /* Don't check when reading keys from a script. That would break the test
4298 * scripts */
4299 if (using_script())
4300 return;
4301
4302 /* Only do this at regular intervals */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004303 if (++count < frequency)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304 return;
4305 count = 0;
4306
4307 ++no_mapping;
4308 c = vpeekc_any();
4309 --no_mapping;
4310 if (c != NUL)
4311 {
4312 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
4313 {
4314 c = safe_vgetc(); /* Eat the character */
Bram Moolenaare3226be2005-12-18 22:10:00 +00004315 compl_shows_dir = ins_compl_key2dir(c);
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004316 (void)ins_compl_next(FALSE, ins_compl_key2count(c),
4317 c != K_UP && c != K_DOWN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318 }
4319 else if (c != Ctrl_R)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004320 compl_interrupted = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 }
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004322 if (compl_pending != 0 && !got_int)
4323 (void)ins_compl_next(FALSE, compl_pending > 0
4324 ? compl_pending : -compl_pending, TRUE);
Bram Moolenaare3226be2005-12-18 22:10:00 +00004325}
4326
4327/*
4328 * Decide the direction of Insert mode complete from the key typed.
4329 * Returns BACKWARD or FORWARD.
4330 */
4331 static int
4332ins_compl_key2dir(c)
4333 int c;
4334{
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004335 if (c == Ctrl_P || c == Ctrl_L
4336 || (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP
4337 || c == K_S_UP || c == K_UP)))
Bram Moolenaare3226be2005-12-18 22:10:00 +00004338 return BACKWARD;
4339 return FORWARD;
4340}
4341
4342/*
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004343 * Return TRUE for keys that are used for completion only when the popup menu
4344 * is visible.
4345 */
4346 static int
4347ins_compl_pum_key(c)
4348 int c;
4349{
4350 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004351 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
4352 || c == K_UP || c == K_DOWN);
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004353}
4354
4355/*
Bram Moolenaare3226be2005-12-18 22:10:00 +00004356 * Decide the number of completions to move forward.
4357 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4358 */
4359 static int
4360ins_compl_key2count(c)
4361 int c;
4362{
4363 int h;
4364
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004365 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
Bram Moolenaare3226be2005-12-18 22:10:00 +00004366 {
4367 h = pum_get_height();
4368 if (h > 3)
4369 h -= 2; /* keep some context */
4370 return h;
4371 }
4372 return 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373}
4374
4375/*
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004376 * Return TRUE if completion with "c" should insert the match, FALSE if only
4377 * to change the currently selected completion.
4378 */
4379 static int
4380ins_compl_use_match(c)
4381 int c;
4382{
4383 switch (c)
4384 {
4385 case K_UP:
4386 case K_DOWN:
4387 case K_PAGEDOWN:
4388 case K_KPAGEDOWN:
4389 case K_S_DOWN:
4390 case K_PAGEUP:
4391 case K_KPAGEUP:
4392 case K_S_UP:
4393 return FALSE;
4394 }
4395 return TRUE;
4396}
4397
4398/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 * Do Insert mode completion.
4400 * Called when character "c" was typed, which has a meaning for completion.
4401 * Returns OK if completion was done, FAIL if something failed (out of mem).
4402 */
4403 static int
4404ins_complete(c)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004405 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004407 char_u *line;
4408 int startcol = 0; /* column where searched text starts */
4409 colnr_T curs_col; /* cursor column */
4410 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411
Bram Moolenaare3226be2005-12-18 22:10:00 +00004412 compl_direction = ins_compl_key2dir(c);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004413 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 {
4415 /* First time we hit ^N or ^P (in a row, I mean) */
4416
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417 did_ai = FALSE;
4418#ifdef FEAT_SMARTINDENT
4419 did_si = FALSE;
4420 can_si = FALSE;
4421 can_si_back = FALSE;
4422#endif
4423 if (stop_arrow() == FAIL)
4424 return FAIL;
4425
4426 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004427 curs_col = curwin->w_cursor.col;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004428 compl_pending = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429
4430 /* if this same ctrl_x_mode has been interrupted use the text from
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004431 * "compl_startpos" to the cursor as a pattern to add a new word
4432 * instead of expand the one before the cursor, in word-wise if
4433 * "compl_startpos"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 * is not in the same line as the cursor then fix it (the line has
4435 * been split because it was longer than 'tw'). if SOL is set then
4436 * skip the previous pattern, a word at the beginning of the line has
4437 * been inserted, we'll look for that -- Acevedo. */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004438 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4439 && compl_cont_mode == ctrl_x_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 {
4441 /*
4442 * it is a continued search
4443 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004444 compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
4446 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4447 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004448 if (compl_startpos.lnum != curwin->w_cursor.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004450 /* line (probably) wrapped, set compl_startpos to the
4451 * first non_blank in the line, if it is not a wordchar
4452 * include it to get a better pattern, but then we don't
4453 * want the "\\<" prefix, check it bellow */
4454 compl_col = (colnr_T)(skipwhite(line) - line);
4455 compl_startpos.col = compl_col;
4456 compl_startpos.lnum = curwin->w_cursor.lnum;
4457 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458 }
4459 else
4460 {
4461 /* S_IPOS was set when we inserted a word that was at the
4462 * beginning of the line, which means that we'll go to SOL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004463 * mode but first we need to redefine compl_startpos */
4464 if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004466 compl_cont_status |= CONT_SOL;
4467 compl_startpos.col = (colnr_T)(skipwhite(
4468 line + compl_length
4469 + compl_startpos.col) - line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004471 compl_col = compl_startpos.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004473 compl_length = curwin->w_cursor.col - (int)compl_col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004474 /* IObuff is used to add a "word from the next line" would we
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 * have enough space? just being paranoic */
4476#define MIN_SPACE 75
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004477 if (compl_length > (IOSIZE - MIN_SPACE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004479 compl_cont_status &= ~CONT_SOL;
4480 compl_length = (IOSIZE - MIN_SPACE);
4481 compl_col = curwin->w_cursor.col - compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004483 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4484 if (compl_length < 1)
4485 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 }
4487 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004488 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004490 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 }
4492 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004493 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004495 if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004497 compl_cont_mode = ctrl_x_mode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004499 compl_cont_status = 0;
4500 compl_cont_status |= CONT_N_ADDS;
4501 compl_startpos = curwin->w_cursor;
4502 startcol = (int)curs_col;
4503 compl_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504 }
4505
4506 /* Work out completion pattern and original text -- webb */
4507 if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
4508 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004509 if ((compl_cont_status & CONT_SOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
4511 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004512 if (!(compl_cont_status & CONT_ADDING))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004514 while (--startcol >= 0 && vim_isIDc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004516 compl_col += ++startcol;
4517 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 }
4519 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004520 compl_pattern = str_foldcase(line + compl_col,
4521 compl_length, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004523 compl_pattern = vim_strnsave(line + compl_col,
4524 compl_length);
4525 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 return FAIL;
4527 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004528 else if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 {
4530 char_u *prefix = (char_u *)"\\<";
4531
4532 /* we need 3 extra chars, 1 for the NUL and
4533 * 2 >= strlen(prefix) -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004534 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4535 compl_length) + 3);
4536 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004538 if (!vim_iswordp(line + compl_col)
4539 || (compl_col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 && (
4541#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004542 vim_iswordp(mb_prevptr(line, line + compl_col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004544 vim_iswordc(line[compl_col - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545#endif
4546 )))
4547 prefix = (char_u *)"";
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004548 STRCPY((char *)compl_pattern, prefix);
4549 (void)quote_meta(compl_pattern + STRLEN(prefix),
4550 line + compl_col, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004552 else if (--startcol < 0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004554 !vim_iswordp(mb_prevptr(line, line + startcol + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004556 !vim_iswordc(line[startcol])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557#endif
4558 )
4559 {
4560 /* Match any word of at least two chars */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004561 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4562 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004564 compl_col += curs_col;
4565 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566 }
4567 else
4568 {
4569#ifdef FEAT_MBYTE
4570 /* Search the point of change class of multibyte character
4571 * or not a word single byte character backward. */
4572 if (has_mbyte)
4573 {
4574 int base_class;
4575 int head_off;
4576
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004577 startcol -= (*mb_head_off)(line, line + startcol);
4578 base_class = mb_get_class(line + startcol);
4579 while (--startcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004581 head_off = (*mb_head_off)(line, line + startcol);
4582 if (base_class != mb_get_class(line + startcol
4583 - head_off))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004585 startcol -= head_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586 }
4587 }
4588 else
4589#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004590 while (--startcol >= 0 && vim_iswordc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004592 compl_col += ++startcol;
4593 compl_length = (int)curs_col - startcol;
4594 if (compl_length == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004595 {
4596 /* Only match word with at least two chars -- webb
4597 * there's no need to call quote_meta,
4598 * alloc(7) is enough -- Acevedo
4599 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004600 compl_pattern = alloc(7);
4601 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004603 STRCPY((char *)compl_pattern, "\\<");
4604 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4605 STRCAT((char *)compl_pattern, "\\k");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 }
4607 else
4608 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004609 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4610 compl_length) + 3);
4611 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004613 STRCPY((char *)compl_pattern, "\\<");
4614 (void)quote_meta(compl_pattern + 2, line + compl_col,
4615 compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 }
4617 }
4618 }
4619 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4620 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004621 compl_col = (colnr_T)(skipwhite(line) - line);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004622 compl_length = (int)curs_col - (int)compl_col;
4623 if (compl_length < 0) /* cursor in indent: empty pattern */
4624 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004626 compl_pattern = str_foldcase(line + compl_col, compl_length,
4627 NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004629 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4630 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 return FAIL;
4632 }
4633 else if (ctrl_x_mode == CTRL_X_FILES)
4634 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004635 while (--startcol >= 0 && vim_isfilec(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004637 compl_col += ++startcol;
4638 compl_length = (int)curs_col - startcol;
4639 compl_pattern = addstar(line + compl_col, compl_length,
4640 EXPAND_FILES);
4641 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 return FAIL;
4643 }
4644 else if (ctrl_x_mode == CTRL_X_CMDLINE)
4645 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004646 compl_pattern = vim_strnsave(line, curs_col);
4647 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004649 set_cmd_context(&compl_xp, compl_pattern,
4650 (int)STRLEN(compl_pattern), curs_col);
4651 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4652 || compl_xp.xp_context == EXPAND_NOTHING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004654 startcol = (int)(compl_xp.xp_pattern - compl_pattern);
4655 compl_col = startcol;
4656 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 }
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004658 else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004659 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00004660#ifdef FEAT_COMPL_FUNC
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004661 /*
Bram Moolenaare344bea2005-09-01 20:46:49 +00004662 * Call user defined function 'completefunc' with "a:findstart"
4663 * set to 1 to obtain the length of text to use for completion.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004664 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00004665 char_u *args[2];
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004666 int col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00004667 char_u *funcname;
4668 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004669
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004670 /* Call 'completefunc' or 'omnifunc' and get pattern length as a
Bram Moolenaare344bea2005-09-01 20:46:49 +00004671 * string */
4672 funcname = ctrl_x_mode == CTRL_X_FUNCTION
4673 ? curbuf->b_p_cfu : curbuf->b_p_ofu;
4674 if (*funcname == NUL)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004675 {
4676 EMSG2(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
4677 ? "completefunc" : "omnifunc");
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004678 return FAIL;
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004679 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004680
4681 args[0] = (char_u *)"1";
Bram Moolenaare344bea2005-09-01 20:46:49 +00004682 args[1] = NULL;
4683 pos = curwin->w_cursor;
4684 col = call_func_retnr(funcname, 2, args, FALSE);
4685 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004686
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004687 if (col < 0)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00004688 col = curs_col;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004689 compl_col = col;
4690 if ((colnr_T)compl_col > curs_col)
4691 compl_col = curs_col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004692
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004693 /* Setup variables for completion. Need to obtain "line" again,
4694 * it may have become invalid. */
4695 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00004696 compl_length = curs_col - compl_col;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004697 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4698 if (compl_pattern == NULL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00004699#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004700 return FAIL;
4701 }
Bram Moolenaar488c6512005-08-11 20:09:58 +00004702 else if (ctrl_x_mode == CTRL_X_SPELL)
4703 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00004704#ifdef FEAT_SPELL
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +00004705 if (spell_bad_len > 0)
4706 compl_col = curs_col - spell_bad_len;
4707 else
4708 compl_col = spell_word_start(startcol);
4709 if (compl_col >= (colnr_T)startcol)
Bram Moolenaar488c6512005-08-11 20:09:58 +00004710 return FAIL;
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00004711 spell_expand_check_cap(compl_col);
Bram Moolenaare2f98b92006-03-29 21:18:24 +00004712 /* Need to obtain "line" again, it may have become invalid. */
4713 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar488c6512005-08-11 20:09:58 +00004714 compl_length = (int)curs_col - compl_col;
4715 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4716 if (compl_pattern == NULL)
4717#endif
4718 return FAIL;
4719 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004720 else
4721 {
4722 EMSG2(_(e_intern2), "ins_complete()");
4723 return FAIL;
4724 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004726 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 {
4728 edit_submode_pre = (char_u *)_(" Adding");
4729 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
4730 {
4731 /* Insert a new line, keep indentation but ignore 'comments' */
4732#ifdef FEAT_COMMENTS
4733 char_u *old = curbuf->b_p_com;
4734
4735 curbuf->b_p_com = (char_u *)"";
4736#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004737 compl_startpos.lnum = curwin->w_cursor.lnum;
4738 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 ins_eol('\r');
4740#ifdef FEAT_COMMENTS
4741 curbuf->b_p_com = old;
4742#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004743 compl_length = 0;
4744 compl_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745 }
4746 }
4747 else
4748 {
4749 edit_submode_pre = NULL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004750 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 }
4752
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004753 if (compl_cont_status & CONT_LOCAL)
4754 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 else
4756 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
4757
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00004758 /* Always add completion for the original text. */
4759 vim_free(compl_orig_text);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004760 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
4761 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar4a85b412006-04-23 22:40:29 +00004762 -1, FALSE, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004764 vim_free(compl_pattern);
4765 compl_pattern = NULL;
4766 vim_free(compl_orig_text);
4767 compl_orig_text = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 return FAIL;
4769 }
4770
4771 /* showmode might reset the internal line pointers, so it must
4772 * be called before line = ml_get(), or when this address is no
4773 * longer needed. -- Acevedo.
4774 */
4775 edit_submode_extra = (char_u *)_("-- Searching...");
4776 edit_submode_highl = HLF_COUNT;
4777 showmode();
4778 edit_submode_extra = NULL;
4779 out_flush();
4780 }
4781
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004782 compl_shown_match = compl_curr_match;
4783 compl_shows_dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784
4785 /*
Bram Moolenaarc7453f52006-02-10 23:20:28 +00004786 * Find next match (and following matches).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004788 n = ins_compl_next(TRUE, ins_compl_key2count(c), ins_compl_use_match(c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004790 /* may undisplay the popup menu */
4791 ins_compl_upd_pum();
4792
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004793 if (n > 1) /* all matches have been found */
4794 compl_matches = n;
4795 compl_curr_match = compl_shown_match;
4796 compl_direction = compl_shows_dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797
Bram Moolenaard68071d2006-05-02 22:08:30 +00004798 /* Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
4799 * mode. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800 if (got_int && !global_busy)
4801 {
4802 (void)vgetc();
4803 got_int = FALSE;
4804 }
4805
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004806 /* we found no match if the list has only the "compl_orig_text"-entry */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004807 if (compl_first_match == compl_first_match->cp_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004809 edit_submode_extra = (compl_cont_status & CONT_ADDING)
4810 && compl_length > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
4812 edit_submode_highl = HLF_E;
4813 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
4814 * because we couldn't expand anything at first place, but if we used
4815 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
4816 * (such as M in M'exico) if not tried already. -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004817 if ( compl_length > 1
4818 || (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819 || (ctrl_x_mode != 0
4820 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
4821 && ctrl_x_mode != CTRL_X_PATH_DEFINES))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004822 compl_cont_status &= ~CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 }
4824
Bram Moolenaar572cb562005-08-05 21:35:02 +00004825 if (compl_curr_match->cp_flags & CONT_S_IPOS)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004826 compl_cont_status |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004828 compl_cont_status &= ~CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829
4830 if (edit_submode_extra == NULL)
4831 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004832 if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 {
4834 edit_submode_extra = (char_u *)_("Back at original");
4835 edit_submode_highl = HLF_W;
4836 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004837 else if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 {
4839 edit_submode_extra = (char_u *)_("Word from other line");
4840 edit_submode_highl = HLF_COUNT;
4841 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004842 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 {
4844 edit_submode_extra = (char_u *)_("The only match");
4845 edit_submode_highl = HLF_COUNT;
4846 }
4847 else
4848 {
4849 /* Update completion sequence number when needed. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004850 if (compl_curr_match->cp_number == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004852 int number = 0;
4853 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004854
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004855 if (compl_direction == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856 {
4857 /* search backwards for the first valid (!= -1) number.
4858 * This should normally succeed already at the first loop
4859 * cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004860 for (match = compl_curr_match->cp_prev; match != NULL
4861 && match != compl_first_match;
4862 match = match->cp_prev)
4863 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004864 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004865 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 break;
4867 }
4868 if (match != NULL)
4869 /* go up and assign all numbers which are not assigned
4870 * yet */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004871 for (match = match->cp_next;
4872 match != NULL && match->cp_number == -1;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004873 match = match->cp_next)
4874 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875 }
4876 else /* BACKWARD */
4877 {
4878 /* search forwards (upwards) for the first valid (!= -1)
4879 * number. This should normally succeed already at the
4880 * first loop cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004881 for (match = compl_curr_match->cp_next; match != NULL
4882 && match != compl_first_match;
4883 match = match->cp_next)
4884 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004885 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00004886 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887 break;
4888 }
4889 if (match != NULL)
4890 /* go down and assign all numbers which are not
4891 * assigned yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004892 for (match = match->cp_prev; match
4893 && match->cp_number == -1;
4894 match = match->cp_prev)
4895 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896 }
4897 }
4898
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004899 /* The match should always have a sequence number now, this is
4900 * just a safety check. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00004901 if (compl_curr_match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004902 {
4903 /* Space for 10 text chars. + 2x10-digit no.s */
4904 static char_u match_ref[31];
4905
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004906 if (compl_matches > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 sprintf((char *)IObuff, _("match %d of %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004908 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004910 sprintf((char *)IObuff, _("match %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00004911 compl_curr_match->cp_number);
Bram Moolenaarce0842a2005-07-18 21:58:11 +00004912 vim_strncpy(match_ref, IObuff, 30);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913 edit_submode_extra = match_ref;
4914 edit_submode_highl = HLF_R;
4915 if (dollar_vcol)
4916 curs_columns(FALSE);
4917 }
4918 }
4919 }
4920
4921 /* Show a message about what (completion) mode we're in. */
4922 showmode();
4923 if (edit_submode_extra != NULL)
4924 {
4925 if (!p_smd)
4926 msg_attr(edit_submode_extra,
4927 edit_submode_highl < HLF_COUNT
4928 ? hl_attr(edit_submode_highl) : 0);
4929 }
4930 else
4931 msg_clr_cmdline(); /* necessary for "noshowmode" */
4932
Bram Moolenaard68071d2006-05-02 22:08:30 +00004933 /* Show the popup menu, unless we got interrupted. */
4934 if (!compl_interrupted)
4935 {
4936 /* RedrawingDisabled may be set when invoked through complete(). */
4937 n = RedrawingDisabled;
4938 RedrawingDisabled = 0;
4939 ins_compl_show_pum();
4940 setcursor();
4941 RedrawingDisabled = n;
4942 }
Bram Moolenaar1423b9d2006-05-07 15:16:06 +00004943 compl_was_interrupted = compl_interrupted;
Bram Moolenaard68071d2006-05-02 22:08:30 +00004944 compl_interrupted = FALSE;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00004945
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946 return OK;
4947}
4948
4949/*
4950 * Looks in the first "len" chars. of "src" for search-metachars.
4951 * If dest is not NULL the chars. are copied there quoting (with
4952 * a backslash) the metachars, and dest would be NUL terminated.
4953 * Returns the length (needed) of dest
4954 */
4955 static int
4956quote_meta(dest, src, len)
4957 char_u *dest;
4958 char_u *src;
4959 int len;
4960{
4961 int m;
4962
4963 for (m = len; --len >= 0; src++)
4964 {
4965 switch (*src)
4966 {
4967 case '.':
4968 case '*':
4969 case '[':
4970 if (ctrl_x_mode == CTRL_X_DICTIONARY
4971 || ctrl_x_mode == CTRL_X_THESAURUS)
4972 break;
4973 case '~':
4974 if (!p_magic) /* quote these only if magic is set */
4975 break;
4976 case '\\':
4977 if (ctrl_x_mode == CTRL_X_DICTIONARY
4978 || ctrl_x_mode == CTRL_X_THESAURUS)
4979 break;
4980 case '^': /* currently it's not needed. */
4981 case '$':
4982 m++;
4983 if (dest != NULL)
4984 *dest++ = '\\';
4985 break;
4986 }
4987 if (dest != NULL)
4988 *dest++ = *src;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004989# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990 /* Copy remaining bytes of a multibyte character. */
4991 if (has_mbyte)
4992 {
4993 int i, mb_len;
4994
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004995 mb_len = (*mb_ptr2len)(src) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996 if (mb_len > 0 && len >= mb_len)
4997 for (i = 0; i < mb_len; ++i)
4998 {
4999 --len;
5000 ++src;
5001 if (dest != NULL)
5002 *dest++ = *src;
5003 }
5004 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00005005# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005006 }
5007 if (dest != NULL)
5008 *dest = NUL;
5009
5010 return m;
5011}
5012#endif /* FEAT_INS_EXPAND */
5013
5014/*
5015 * Next character is interpreted literally.
5016 * A one, two or three digit decimal number is interpreted as its byte value.
5017 * If one or two digits are entered, the next character is given to vungetc().
5018 * For Unicode a character > 255 may be returned.
5019 */
5020 int
5021get_literal()
5022{
5023 int cc;
5024 int nc;
5025 int i;
5026 int hex = FALSE;
5027 int octal = FALSE;
5028#ifdef FEAT_MBYTE
5029 int unicode = 0;
5030#endif
5031
5032 if (got_int)
5033 return Ctrl_C;
5034
5035#ifdef FEAT_GUI
5036 /*
5037 * In GUI there is no point inserting the internal code for a special key.
5038 * It is more useful to insert the string "<KEY>" instead. This would
5039 * probably be useful in a text window too, but it would not be
5040 * vi-compatible (maybe there should be an option for it?) -- webb
5041 */
5042 if (gui.in_use)
5043 ++allow_keys;
5044#endif
5045#ifdef USE_ON_FLY_SCROLL
5046 dont_scroll = TRUE; /* disallow scrolling here */
5047#endif
5048 ++no_mapping; /* don't map the next key hits */
5049 cc = 0;
5050 i = 0;
5051 for (;;)
5052 {
5053 do
5054 nc = safe_vgetc();
5055 while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
5056 || nc == K_HOR_SCROLLBAR);
5057#ifdef FEAT_CMDL_INFO
5058 if (!(State & CMDLINE)
5059# ifdef FEAT_MBYTE
5060 && MB_BYTE2LEN_CHECK(nc) == 1
5061# endif
5062 )
5063 add_to_showcmd(nc);
5064#endif
5065 if (nc == 'x' || nc == 'X')
5066 hex = TRUE;
5067 else if (nc == 'o' || nc == 'O')
5068 octal = TRUE;
5069#ifdef FEAT_MBYTE
5070 else if (nc == 'u' || nc == 'U')
5071 unicode = nc;
5072#endif
5073 else
5074 {
5075 if (hex
5076#ifdef FEAT_MBYTE
5077 || unicode != 0
5078#endif
5079 )
5080 {
5081 if (!vim_isxdigit(nc))
5082 break;
5083 cc = cc * 16 + hex2nr(nc);
5084 }
5085 else if (octal)
5086 {
5087 if (nc < '0' || nc > '7')
5088 break;
5089 cc = cc * 8 + nc - '0';
5090 }
5091 else
5092 {
5093 if (!VIM_ISDIGIT(nc))
5094 break;
5095 cc = cc * 10 + nc - '0';
5096 }
5097
5098 ++i;
5099 }
5100
5101 if (cc > 255
5102#ifdef FEAT_MBYTE
5103 && unicode == 0
5104#endif
5105 )
5106 cc = 255; /* limit range to 0-255 */
5107 nc = 0;
5108
5109 if (hex) /* hex: up to two chars */
5110 {
5111 if (i >= 2)
5112 break;
5113 }
5114#ifdef FEAT_MBYTE
5115 else if (unicode) /* Unicode: up to four or eight chars */
5116 {
5117 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
5118 break;
5119 }
5120#endif
5121 else if (i >= 3) /* decimal or octal: up to three chars */
5122 break;
5123 }
5124 if (i == 0) /* no number entered */
5125 {
5126 if (nc == K_ZERO) /* NUL is stored as NL */
5127 {
5128 cc = '\n';
5129 nc = 0;
5130 }
5131 else
5132 {
5133 cc = nc;
5134 nc = 0;
5135 }
5136 }
5137
5138 if (cc == 0) /* NUL is stored as NL */
5139 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00005140#ifdef FEAT_MBYTE
5141 if (enc_dbcs && (cc & 0xff) == 0)
5142 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
5143 second byte will cause trouble! */
5144#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145
5146 --no_mapping;
5147#ifdef FEAT_GUI
5148 if (gui.in_use)
5149 --allow_keys;
5150#endif
5151 if (nc)
5152 vungetc(nc);
5153 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
5154 return cc;
5155}
5156
5157/*
5158 * Insert character, taking care of special keys and mod_mask
5159 */
5160 static void
5161insert_special(c, allow_modmask, ctrlv)
5162 int c;
5163 int allow_modmask;
5164 int ctrlv; /* c was typed after CTRL-V */
5165{
5166 char_u *p;
5167 int len;
5168
5169 /*
5170 * Special function key, translate into "<Key>". Up to the last '>' is
5171 * inserted with ins_str(), so as not to replace characters in replace
5172 * mode.
5173 * Only use mod_mask for special keys, to avoid things like <S-Space>,
5174 * unless 'allow_modmask' is TRUE.
5175 */
5176#ifdef MACOS
5177 /* Command-key never produces a normal key */
5178 if (mod_mask & MOD_MASK_CMD)
5179 allow_modmask = TRUE;
5180#endif
5181 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
5182 {
5183 p = get_special_key_name(c, mod_mask);
5184 len = (int)STRLEN(p);
5185 c = p[len - 1];
5186 if (len > 2)
5187 {
5188 if (stop_arrow() == FAIL)
5189 return;
5190 p[len - 1] = NUL;
5191 ins_str(p);
Bram Moolenaarebefac62005-12-28 22:39:57 +00005192 AppendToRedobuffLit(p, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193 ctrlv = FALSE;
5194 }
5195 }
5196 if (stop_arrow() == OK)
5197 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
5198}
5199
5200/*
5201 * Special characters in this context are those that need processing other
5202 * than the simple insertion that can be performed here. This includes ESC
5203 * which terminates the insert, and CR/NL which need special processing to
5204 * open up a new line. This routine tries to optimize insertions performed by
5205 * the "redo", "undo" or "put" commands, so it needs to know when it should
5206 * stop and defer processing to the "normal" mechanism.
5207 * '0' and '^' are special, because they can be followed by CTRL-D.
5208 */
5209#ifdef EBCDIC
5210# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
5211#else
5212# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
5213#endif
5214
5215#ifdef FEAT_MBYTE
5216# define WHITECHAR(cc) (vim_iswhite(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
5217#else
5218# define WHITECHAR(cc) vim_iswhite(cc)
5219#endif
5220
5221 void
5222insertchar(c, flags, second_indent)
5223 int c; /* character to insert or NUL */
5224 int flags; /* INSCHAR_FORMAT, etc. */
5225 int second_indent; /* indent for second line if >= 0 */
5226{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227 int textwidth;
5228#ifdef FEAT_COMMENTS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005231 int fo_ins_blank;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232
5233 textwidth = comp_textwidth(flags & INSCHAR_FORMAT);
5234 fo_ins_blank = has_format_option(FO_INS_BLANK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235
5236 /*
5237 * Try to break the line in two or more pieces when:
5238 * - Always do this if we have been called to do formatting only.
5239 * - Always do this when 'formatoptions' has the 'a' flag and the line
5240 * ends in white space.
5241 * - Otherwise:
5242 * - Don't do this if inserting a blank
5243 * - Don't do this if an existing character is being replaced, unless
5244 * we're in VREPLACE mode.
5245 * - Do this if the cursor is not on the line where insert started
5246 * or - 'formatoptions' doesn't have 'l' or the line was not too long
5247 * before the insert.
5248 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
5249 * before 'textwidth'
5250 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005251 if (textwidth > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 && ((flags & INSCHAR_FORMAT)
5253 || (!vim_iswhite(c)
5254 && !((State & REPLACE_FLAG)
5255#ifdef FEAT_VREPLACE
5256 && !(State & VREPLACE_FLAG)
5257#endif
5258 && *ml_get_cursor() != NUL)
5259 && (curwin->w_cursor.lnum != Insstart.lnum
5260 || ((!has_format_option(FO_INS_LONG)
5261 || Insstart_textlen <= (colnr_T)textwidth)
5262 && (!fo_ins_blank
5263 || Insstart_blank_vcol <= (colnr_T)textwidth
5264 ))))))
5265 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005266 /* Format with 'formatexpr' when it's set. Use internal formatting
5267 * when 'formatexpr' isn't set or it returns non-zero. */
5268#if defined(FEAT_EVAL)
5269 if (*curbuf->b_p_fex == NUL
Bram Moolenaarf193fff2006-04-27 00:02:13 +00005270 || fex_format(curwin->w_cursor.lnum, 1L, c) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005272 internal_format(textwidth, second_indent, flags, c == NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005274
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275 if (c == NUL) /* only formatting was wanted */
5276 return;
5277
5278#ifdef FEAT_COMMENTS
5279 /* Check whether this character should end a comment. */
5280 if (did_ai && (int)c == end_comment_pending)
5281 {
5282 char_u *line;
5283 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
5284 int middle_len, end_len;
5285 int i;
5286
5287 /*
5288 * Need to remove existing (middle) comment leader and insert end
5289 * comment leader. First, check what comment leader we can find.
5290 */
5291 i = get_leader_len(line = ml_get_curline(), &p, FALSE);
5292 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
5293 {
5294 /* Skip middle-comment string */
5295 while (*p && p[-1] != ':') /* find end of middle flags */
5296 ++p;
5297 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5298 /* Don't count trailing white space for middle_len */
5299 while (middle_len > 0 && vim_iswhite(lead_end[middle_len - 1]))
5300 --middle_len;
5301
5302 /* Find the end-comment string */
5303 while (*p && p[-1] != ':') /* find end of end flags */
5304 ++p;
5305 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5306
5307 /* Skip white space before the cursor */
5308 i = curwin->w_cursor.col;
5309 while (--i >= 0 && vim_iswhite(line[i]))
5310 ;
5311 i++;
5312
5313 /* Skip to before the middle leader */
5314 i -= middle_len;
5315
5316 /* Check some expected things before we go on */
5317 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
5318 {
5319 /* Backspace over all the stuff we want to replace */
5320 backspace_until_column(i);
5321
5322 /*
5323 * Insert the end-comment string, except for the last
5324 * character, which will get inserted as normal later.
5325 */
5326 ins_bytes_len(lead_end, end_len - 1);
5327 }
5328 }
5329 }
5330 end_comment_pending = NUL;
5331#endif
5332
5333 did_ai = FALSE;
5334#ifdef FEAT_SMARTINDENT
5335 did_si = FALSE;
5336 can_si = FALSE;
5337 can_si_back = FALSE;
5338#endif
5339
5340 /*
5341 * If there's any pending input, grab up to INPUT_BUFLEN at once.
5342 * This speeds up normal text input considerably.
5343 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
5344 * need to re-indent at a ':', or any other character (but not what
5345 * 'paste' is set)..
5346 */
5347#ifdef USE_ON_FLY_SCROLL
5348 dont_scroll = FALSE; /* allow scrolling here */
5349#endif
5350
5351 if ( !ISSPECIAL(c)
5352#ifdef FEAT_MBYTE
5353 && (!has_mbyte || (*mb_char2len)(c) == 1)
5354#endif
5355 && vpeekc() != NUL
5356 && !(State & REPLACE_FLAG)
5357#ifdef FEAT_CINDENT
5358 && !cindent_on()
5359#endif
5360#ifdef FEAT_RIGHTLEFT
5361 && !p_ri
5362#endif
5363 )
5364 {
5365#define INPUT_BUFLEN 100
5366 char_u buf[INPUT_BUFLEN + 1];
5367 int i;
5368 colnr_T virtcol = 0;
5369
5370 buf[0] = c;
5371 i = 1;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005372 if (textwidth > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373 virtcol = get_nolist_virtcol();
5374 /*
5375 * Stop the string when:
5376 * - no more chars available
5377 * - finding a special character (command key)
5378 * - buffer is full
5379 * - running into the 'textwidth' boundary
5380 * - need to check for abbreviation: A non-word char after a word-char
5381 */
5382 while ( (c = vpeekc()) != NUL
5383 && !ISSPECIAL(c)
5384#ifdef FEAT_MBYTE
5385 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
5386#endif
5387 && i < INPUT_BUFLEN
5388 && (textwidth == 0
5389 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
5390 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
5391 {
5392#ifdef FEAT_RIGHTLEFT
5393 c = vgetc();
5394 if (p_hkmap && KeyTyped)
5395 c = hkmap(c); /* Hebrew mode mapping */
5396# ifdef FEAT_FKMAP
5397 if (p_fkmap && KeyTyped)
5398 c = fkmap(c); /* Farsi mode mapping */
5399# endif
5400 buf[i++] = c;
5401#else
5402 buf[i++] = vgetc();
5403#endif
5404 }
5405
5406#ifdef FEAT_DIGRAPHS
5407 do_digraph(-1); /* clear digraphs */
5408 do_digraph(buf[i-1]); /* may be the start of a digraph */
5409#endif
5410 buf[i] = NUL;
5411 ins_str(buf);
5412 if (flags & INSCHAR_CTRLV)
5413 {
5414 redo_literal(*buf);
5415 i = 1;
5416 }
5417 else
5418 i = 0;
5419 if (buf[i] != NUL)
Bram Moolenaarebefac62005-12-28 22:39:57 +00005420 AppendToRedobuffLit(buf + i, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005421 }
5422 else
5423 {
5424#ifdef FEAT_MBYTE
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005425 int cc;
5426
Bram Moolenaar071d4272004-06-13 20:20:40 +00005427 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
5428 {
5429 char_u buf[MB_MAXBYTES + 1];
5430
5431 (*mb_char2bytes)(c, buf);
5432 buf[cc] = NUL;
5433 ins_char_bytes(buf, cc);
5434 AppendCharToRedobuff(c);
5435 }
5436 else
5437#endif
5438 {
5439 ins_char(c);
5440 if (flags & INSCHAR_CTRLV)
5441 redo_literal(c);
5442 else
5443 AppendCharToRedobuff(c);
5444 }
5445 }
5446}
5447
5448/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005449 * Format text at the current insert position.
5450 */
5451 static void
5452internal_format(textwidth, second_indent, flags, format_only)
5453 int textwidth;
5454 int second_indent;
5455 int flags;
5456 int format_only;
5457{
5458 int cc;
5459 int save_char = NUL;
5460 int haveto_redraw = FALSE;
5461 int fo_ins_blank = has_format_option(FO_INS_BLANK);
5462#ifdef FEAT_MBYTE
5463 int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
5464#endif
5465 int fo_white_par = has_format_option(FO_WHITE_PAR);
5466 int first_line = TRUE;
5467#ifdef FEAT_COMMENTS
5468 colnr_T leader_len;
5469 int no_leader = FALSE;
5470 int do_comments = (flags & INSCHAR_DO_COM);
5471#endif
5472
5473 /*
5474 * When 'ai' is off we don't want a space under the cursor to be
5475 * deleted. Replace it with an 'x' temporarily.
5476 */
5477 if (!curbuf->b_p_ai)
5478 {
5479 cc = gchar_cursor();
5480 if (vim_iswhite(cc))
5481 {
5482 save_char = cc;
5483 pchar_cursor('x');
5484 }
5485 }
5486
5487 /*
5488 * Repeat breaking lines, until the current line is not too long.
5489 */
5490 while (!got_int)
5491 {
5492 int startcol; /* Cursor column at entry */
5493 int wantcol; /* column at textwidth border */
5494 int foundcol; /* column for start of spaces */
5495 int end_foundcol = 0; /* column for start of word */
5496 colnr_T len;
5497 colnr_T virtcol;
5498#ifdef FEAT_VREPLACE
5499 int orig_col = 0;
5500 char_u *saved_text = NULL;
5501#endif
5502 colnr_T col;
5503
5504 virtcol = get_nolist_virtcol();
5505 if (virtcol < (colnr_T)textwidth)
5506 break;
5507
5508#ifdef FEAT_COMMENTS
5509 if (no_leader)
5510 do_comments = FALSE;
5511 else if (!(flags & INSCHAR_FORMAT)
5512 && has_format_option(FO_WRAP_COMS))
5513 do_comments = TRUE;
5514
5515 /* Don't break until after the comment leader */
5516 if (do_comments)
5517 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE);
5518 else
5519 leader_len = 0;
5520
5521 /* If the line doesn't start with a comment leader, then don't
5522 * start one in a following broken line. Avoids that a %word
5523 * moved to the start of the next line causes all following lines
5524 * to start with %. */
5525 if (leader_len == 0)
5526 no_leader = TRUE;
5527#endif
5528 if (!(flags & INSCHAR_FORMAT)
5529#ifdef FEAT_COMMENTS
5530 && leader_len == 0
5531#endif
5532 && !has_format_option(FO_WRAP))
5533
5534 {
5535 textwidth = 0;
5536 break;
5537 }
5538 if ((startcol = curwin->w_cursor.col) == 0)
5539 break;
5540
5541 /* find column of textwidth border */
5542 coladvance((colnr_T)textwidth);
5543 wantcol = curwin->w_cursor.col;
5544
5545 curwin->w_cursor.col = startcol - 1;
5546#ifdef FEAT_MBYTE
5547 /* Correct cursor for multi-byte character. */
5548 if (has_mbyte)
5549 mb_adjust_cursor();
5550#endif
5551 foundcol = 0;
5552
5553 /*
5554 * Find position to break at.
5555 * Stop at first entered white when 'formatoptions' has 'v'
5556 */
5557 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
5558 || curwin->w_cursor.lnum != Insstart.lnum
5559 || curwin->w_cursor.col >= Insstart.col)
5560 {
5561 cc = gchar_cursor();
5562 if (WHITECHAR(cc))
5563 {
5564 /* remember position of blank just before text */
5565 end_foundcol = curwin->w_cursor.col;
5566
5567 /* find start of sequence of blanks */
5568 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
5569 {
5570 dec_cursor();
5571 cc = gchar_cursor();
5572 }
5573 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
5574 break; /* only spaces in front of text */
5575#ifdef FEAT_COMMENTS
5576 /* Don't break until after the comment leader */
5577 if (curwin->w_cursor.col < leader_len)
5578 break;
5579#endif
5580 if (has_format_option(FO_ONE_LETTER))
5581 {
5582 /* do not break after one-letter words */
5583 if (curwin->w_cursor.col == 0)
5584 break; /* one-letter word at begin */
5585
5586 col = curwin->w_cursor.col;
5587 dec_cursor();
5588 cc = gchar_cursor();
5589
5590 if (WHITECHAR(cc))
5591 continue; /* one-letter, continue */
5592 curwin->w_cursor.col = col;
5593 }
5594#ifdef FEAT_MBYTE
5595 if (has_mbyte)
5596 foundcol = curwin->w_cursor.col
5597 + (*mb_ptr2len)(ml_get_cursor());
5598 else
5599#endif
5600 foundcol = curwin->w_cursor.col + 1;
5601 if (curwin->w_cursor.col < (colnr_T)wantcol)
5602 break;
5603 }
5604#ifdef FEAT_MBYTE
5605 else if (cc >= 0x100 && fo_multibyte
5606 && curwin->w_cursor.col <= (colnr_T)wantcol)
5607 {
5608 /* Break after or before a multi-byte character. */
5609 foundcol = curwin->w_cursor.col;
5610 if (curwin->w_cursor.col < (colnr_T)wantcol)
5611 foundcol += (*mb_char2len)(cc);
5612 end_foundcol = foundcol;
5613 break;
5614 }
5615#endif
5616 if (curwin->w_cursor.col == 0)
5617 break;
5618 dec_cursor();
5619 }
5620
5621 if (foundcol == 0) /* no spaces, cannot break line */
5622 {
5623 curwin->w_cursor.col = startcol;
5624 break;
5625 }
5626
5627 /* Going to break the line, remove any "$" now. */
5628 undisplay_dollar();
5629
5630 /*
5631 * Offset between cursor position and line break is used by replace
5632 * stack functions. VREPLACE does not use this, and backspaces
5633 * over the text instead.
5634 */
5635#ifdef FEAT_VREPLACE
5636 if (State & VREPLACE_FLAG)
5637 orig_col = startcol; /* Will start backspacing from here */
5638 else
5639#endif
5640 replace_offset = startcol - end_foundcol - 1;
5641
5642 /*
5643 * adjust startcol for spaces that will be deleted and
5644 * characters that will remain on top line
5645 */
5646 curwin->w_cursor.col = foundcol;
5647 while (cc = gchar_cursor(), WHITECHAR(cc))
5648 inc_cursor();
5649 startcol -= curwin->w_cursor.col;
5650 if (startcol < 0)
5651 startcol = 0;
5652
5653#ifdef FEAT_VREPLACE
5654 if (State & VREPLACE_FLAG)
5655 {
5656 /*
5657 * In VREPLACE mode, we will backspace over the text to be
5658 * wrapped, so save a copy now to put on the next line.
5659 */
5660 saved_text = vim_strsave(ml_get_cursor());
5661 curwin->w_cursor.col = orig_col;
5662 if (saved_text == NULL)
5663 break; /* Can't do it, out of memory */
5664 saved_text[startcol] = NUL;
5665
5666 /* Backspace over characters that will move to the next line */
5667 if (!fo_white_par)
5668 backspace_until_column(foundcol);
5669 }
5670 else
5671#endif
5672 {
5673 /* put cursor after pos. to break line */
5674 if (!fo_white_par)
5675 curwin->w_cursor.col = foundcol;
5676 }
5677
5678 /*
5679 * Split the line just before the margin.
5680 * Only insert/delete lines, but don't really redraw the window.
5681 */
5682 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
5683 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
5684#ifdef FEAT_COMMENTS
5685 + (do_comments ? OPENLINE_DO_COM : 0)
5686#endif
5687 , old_indent);
5688 old_indent = 0;
5689
5690 replace_offset = 0;
5691 if (first_line)
5692 {
5693 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
5694 second_indent = get_number_indent(curwin->w_cursor.lnum -1);
5695 if (second_indent >= 0)
5696 {
5697#ifdef FEAT_VREPLACE
5698 if (State & VREPLACE_FLAG)
5699 change_indent(INDENT_SET, second_indent, FALSE, NUL);
5700 else
5701#endif
5702 (void)set_indent(second_indent, SIN_CHANGED);
5703 }
5704 first_line = FALSE;
5705 }
5706
5707#ifdef FEAT_VREPLACE
5708 if (State & VREPLACE_FLAG)
5709 {
5710 /*
5711 * In VREPLACE mode we have backspaced over the text to be
5712 * moved, now we re-insert it into the new line.
5713 */
5714 ins_bytes(saved_text);
5715 vim_free(saved_text);
5716 }
5717 else
5718#endif
5719 {
5720 /*
5721 * Check if cursor is not past the NUL off the line, cindent
5722 * may have added or removed indent.
5723 */
5724 curwin->w_cursor.col += startcol;
5725 len = (colnr_T)STRLEN(ml_get_curline());
5726 if (curwin->w_cursor.col > len)
5727 curwin->w_cursor.col = len;
5728 }
5729
5730 haveto_redraw = TRUE;
5731#ifdef FEAT_CINDENT
5732 can_cindent = TRUE;
5733#endif
5734 /* moved the cursor, don't autoindent or cindent now */
5735 did_ai = FALSE;
5736#ifdef FEAT_SMARTINDENT
5737 did_si = FALSE;
5738 can_si = FALSE;
5739 can_si_back = FALSE;
5740#endif
5741 line_breakcheck();
5742 }
5743
5744 if (save_char != NUL) /* put back space after cursor */
5745 pchar_cursor(save_char);
5746
5747 if (!format_only && haveto_redraw)
5748 {
5749 update_topline();
5750 redraw_curbuf_later(VALID);
5751 }
5752}
5753
5754/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005755 * Called after inserting or deleting text: When 'formatoptions' includes the
5756 * 'a' flag format from the current line until the end of the paragraph.
5757 * Keep the cursor at the same position relative to the text.
5758 * The caller must have saved the cursor line for undo, following ones will be
5759 * saved here.
5760 */
5761 void
5762auto_format(trailblank, prev_line)
5763 int trailblank; /* when TRUE also format with trailing blank */
5764 int prev_line; /* may start in previous line */
5765{
5766 pos_T pos;
5767 colnr_T len;
5768 char_u *old;
5769 char_u *new, *pnew;
5770 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005771 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005772
5773 if (!has_format_option(FO_AUTO))
5774 return;
5775
5776 pos = curwin->w_cursor;
5777 old = ml_get_curline();
5778
5779 /* may remove added space */
5780 check_auto_format(FALSE);
5781
5782 /* Don't format in Insert mode when the cursor is on a trailing blank, the
5783 * user might insert normal text next. Also skip formatting when "1" is
5784 * in 'formatoptions' and there is a single character before the cursor.
5785 * Otherwise the line would be broken and when typing another non-white
5786 * next they are not joined back together. */
5787 wasatend = (pos.col == STRLEN(old));
5788 if (*old != NUL && !trailblank && wasatend)
5789 {
5790 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005791 cc = gchar_cursor();
5792 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
5793 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005795 cc = gchar_cursor();
5796 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797 {
5798 curwin->w_cursor = pos;
5799 return;
5800 }
5801 curwin->w_cursor = pos;
5802 }
5803
5804#ifdef FEAT_COMMENTS
5805 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
5806 * comments. */
5807 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
5808 && get_leader_len(old, NULL, FALSE) == 0)
5809 return;
5810#endif
5811
5812 /*
5813 * May start formatting in a previous line, so that after "x" a word is
5814 * moved to the previous line if it fits there now. Only when this is not
5815 * the start of a paragraph.
5816 */
5817 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
5818 {
5819 --curwin->w_cursor.lnum;
5820 if (u_save_cursor() == FAIL)
5821 return;
5822 }
5823
5824 /*
5825 * Do the formatting and restore the cursor position. "saved_cursor" will
5826 * be adjusted for the text formatting.
5827 */
5828 saved_cursor = pos;
5829 format_lines((linenr_T)-1);
5830 curwin->w_cursor = saved_cursor;
5831 saved_cursor.lnum = 0;
5832
5833 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
5834 {
5835 /* "cannot happen" */
5836 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5837 coladvance((colnr_T)MAXCOL);
5838 }
5839 else
5840 check_cursor_col();
5841
5842 /* Insert mode: If the cursor is now after the end of the line while it
5843 * previously wasn't, the line was broken. Because of the rule above we
5844 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
5845 * formatted. */
5846 if (!wasatend && has_format_option(FO_WHITE_PAR))
5847 {
5848 new = ml_get_curline();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005849 len = (colnr_T)STRLEN(new);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005850 if (curwin->w_cursor.col == len)
5851 {
5852 pnew = vim_strnsave(new, len + 2);
5853 pnew[len] = ' ';
5854 pnew[len + 1] = NUL;
5855 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
5856 /* remove the space later */
5857 did_add_space = TRUE;
5858 }
5859 else
5860 /* may remove added space */
5861 check_auto_format(FALSE);
5862 }
5863
5864 check_cursor();
5865}
5866
5867/*
5868 * When an extra space was added to continue a paragraph for auto-formatting,
5869 * delete it now. The space must be under the cursor, just after the insert
5870 * position.
5871 */
5872 static void
5873check_auto_format(end_insert)
5874 int end_insert; /* TRUE when ending Insert mode */
5875{
5876 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005877 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878
5879 if (did_add_space)
5880 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00005881 cc = gchar_cursor();
5882 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 /* Somehow the space was removed already. */
5884 did_add_space = FALSE;
5885 else
5886 {
5887 if (!end_insert)
5888 {
5889 inc_cursor();
5890 c = gchar_cursor();
5891 dec_cursor();
5892 }
5893 if (c != NUL)
5894 {
5895 /* The space is no longer at the end of the line, delete it. */
5896 del_char(FALSE);
5897 did_add_space = FALSE;
5898 }
5899 }
5900 }
5901}
5902
5903/*
5904 * Find out textwidth to be used for formatting:
5905 * if 'textwidth' option is set, use it
5906 * else if 'wrapmargin' option is set, use W_WIDTH(curwin) - 'wrapmargin'
5907 * if invalid value, use 0.
5908 * Set default to window width (maximum 79) for "gq" operator.
5909 */
5910 int
5911comp_textwidth(ff)
Bram Moolenaar91170f82006-05-05 21:15:17 +00005912 int ff; /* force formatting (for "gq" command) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913{
5914 int textwidth;
5915
5916 textwidth = curbuf->b_p_tw;
5917 if (textwidth == 0 && curbuf->b_p_wm)
5918 {
5919 /* The width is the window width minus 'wrapmargin' minus all the
5920 * things that add to the margin. */
5921 textwidth = W_WIDTH(curwin) - curbuf->b_p_wm;
5922#ifdef FEAT_CMDWIN
5923 if (cmdwin_type != 0)
5924 textwidth -= 1;
5925#endif
5926#ifdef FEAT_FOLDING
5927 textwidth -= curwin->w_p_fdc;
5928#endif
5929#ifdef FEAT_SIGNS
5930 if (curwin->w_buffer->b_signlist != NULL
5931# ifdef FEAT_NETBEANS_INTG
5932 || usingNetbeans
5933# endif
5934 )
5935 textwidth -= 1;
5936#endif
5937 if (curwin->w_p_nu)
5938 textwidth -= 8;
5939 }
5940 if (textwidth < 0)
5941 textwidth = 0;
5942 if (ff && textwidth == 0)
5943 {
5944 textwidth = W_WIDTH(curwin) - 1;
5945 if (textwidth > 79)
5946 textwidth = 79;
5947 }
5948 return textwidth;
5949}
5950
5951/*
5952 * Put a character in the redo buffer, for when just after a CTRL-V.
5953 */
5954 static void
5955redo_literal(c)
5956 int c;
5957{
5958 char_u buf[10];
5959
5960 /* Only digits need special treatment. Translate them into a string of
5961 * three digits. */
5962 if (VIM_ISDIGIT(c))
5963 {
5964 sprintf((char *)buf, "%03d", c);
5965 AppendToRedobuff(buf);
5966 }
5967 else
5968 AppendCharToRedobuff(c);
5969}
5970
5971/*
5972 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005973 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974 */
5975 static void
5976start_arrow(end_insert_pos)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005977 pos_T *end_insert_pos; /* can be NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978{
5979 if (!arrow_used) /* something has been inserted */
5980 {
5981 AppendToRedobuff(ESC_STR);
5982 stop_insert(end_insert_pos, FALSE);
5983 arrow_used = TRUE; /* this means we stopped the current insert */
5984 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005985#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005986 check_spell_redraw();
5987#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005988}
5989
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00005990#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00005991/*
5992 * If we skipped highlighting word at cursor, do it now.
5993 * It may be skipped again, thus reset spell_redraw_lnum first.
5994 */
5995 static void
5996check_spell_redraw()
5997{
5998 if (spell_redraw_lnum != 0)
5999 {
6000 linenr_T lnum = spell_redraw_lnum;
6001
6002 spell_redraw_lnum = 0;
6003 redrawWinline(lnum, FALSE);
6004 }
6005}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00006006
6007/*
6008 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
6009 * spelled word, if there is one.
6010 */
6011 static void
6012spell_back_to_badword()
6013{
6014 pos_T tpos = curwin->w_cursor;
6015
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00006016 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00006017 if (curwin->w_cursor.col != tpos.col)
6018 start_arrow(&tpos);
6019}
Bram Moolenaar217ad922005-03-20 22:37:15 +00006020#endif
6021
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022/*
6023 * stop_arrow() is called before a change is made in insert mode.
6024 * If an arrow key has been used, start a new insertion.
6025 * Returns FAIL if undo is impossible, shouldn't insert then.
6026 */
6027 int
6028stop_arrow()
6029{
6030 if (arrow_used)
6031 {
6032 if (u_save_cursor() == OK)
6033 {
6034 arrow_used = FALSE;
6035 ins_need_undo = FALSE;
6036 }
6037 Insstart = curwin->w_cursor; /* new insertion starts here */
6038 Insstart_textlen = linetabsize(ml_get_curline());
6039 ai_col = 0;
6040#ifdef FEAT_VREPLACE
6041 if (State & VREPLACE_FLAG)
6042 {
6043 orig_line_count = curbuf->b_ml.ml_line_count;
6044 vr_lines_changed = 1;
6045 }
6046#endif
6047 ResetRedobuff();
6048 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
Bram Moolenaara9b1e742005-12-19 22:14:58 +00006049 new_insert_skip = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050 }
6051 else if (ins_need_undo)
6052 {
6053 if (u_save_cursor() == OK)
6054 ins_need_undo = FALSE;
6055 }
6056
6057#ifdef FEAT_FOLDING
6058 /* Always open fold at the cursor line when inserting something. */
6059 foldOpenCursor();
6060#endif
6061
6062 return (arrow_used || ins_need_undo ? FAIL : OK);
6063}
6064
6065/*
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006066 * Do a few things to stop inserting.
6067 * "end_insert_pos" is where insert ended. It is NULL when we already jumped
6068 * to another window/buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069 */
6070 static void
6071stop_insert(end_insert_pos, esc)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006072 pos_T *end_insert_pos;
Bram Moolenaar83c465c2005-12-16 21:53:56 +00006073 int esc; /* called by ins_esc() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074{
Bram Moolenaar83c465c2005-12-16 21:53:56 +00006075 int cc;
6076 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077
6078 stop_redo_ins();
6079 replace_flush(); /* abandon replace stack */
6080
6081 /*
Bram Moolenaar83c465c2005-12-16 21:53:56 +00006082 * Save the inserted text for later redo with ^@ and CTRL-A.
6083 * Don't do it when "restart_edit" was set and nothing was inserted,
6084 * otherwise CTRL-O w and then <Left> will clear "last_insert".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006085 */
Bram Moolenaar83c465c2005-12-16 21:53:56 +00006086 ptr = get_inserted();
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00006087 if (did_restart_edit == 0 || (ptr != NULL
6088 && (int)STRLEN(ptr) > new_insert_skip))
Bram Moolenaar83c465c2005-12-16 21:53:56 +00006089 {
6090 vim_free(last_insert);
6091 last_insert = ptr;
6092 last_insert_skip = new_insert_skip;
6093 }
6094 else
6095 vim_free(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006097 if (!arrow_used && end_insert_pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 {
6099 /* Auto-format now. It may seem strange to do this when stopping an
6100 * insertion (or moving the cursor), but it's required when appending
6101 * a line and having it end in a space. But only do it when something
6102 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006103 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006105 pos_T tpos = curwin->w_cursor;
6106
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107 /* When the cursor is at the end of the line after a space the
6108 * formatting will move it to the following word. Avoid that by
6109 * moving the cursor onto the space. */
6110 cc = 'x';
6111 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
6112 {
6113 dec_cursor();
6114 cc = gchar_cursor();
6115 if (!vim_iswhite(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006116 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006117 }
6118
6119 auto_format(TRUE, FALSE);
6120
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006121 if (vim_iswhite(cc))
6122 {
6123 if (gchar_cursor() != NUL)
6124 inc_cursor();
6125#ifdef FEAT_VIRTUALEDIT
6126 /* If the cursor is still at the same character, also keep
6127 * the "coladd". */
6128 if (gchar_cursor() == NUL
6129 && curwin->w_cursor.lnum == tpos.lnum
6130 && curwin->w_cursor.col == tpos.col)
6131 curwin->w_cursor.coladd = tpos.coladd;
6132#endif
6133 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134 }
6135
6136 /* If a space was inserted for auto-formatting, remove it now. */
6137 check_auto_format(TRUE);
6138
6139 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006140 * of the line, and put the cursor back.
6141 * Do this when ESC was used or moving the cursor up/down. */
6142 if (did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006143 && curwin->w_cursor.lnum != end_insert_pos->lnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006145 pos_T tpos = curwin->w_cursor;
6146
6147 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar39f05632006-03-19 22:15:26 +00006148 for (;;)
6149 {
6150 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
6151 --curwin->w_cursor.col;
6152 cc = gchar_cursor();
6153 if (!vim_iswhite(cc))
6154 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006155 (void)del_char(TRUE);
Bram Moolenaar39f05632006-03-19 22:15:26 +00006156 }
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00006157 if (curwin->w_cursor.lnum != tpos.lnum)
6158 curwin->w_cursor = tpos;
6159 else if (cc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160 ++curwin->w_cursor.col; /* put cursor back on the NUL */
6161
6162#ifdef FEAT_VISUAL
6163 /* <C-S-Right> may have started Visual mode, adjust the position for
6164 * deleted characters. */
6165 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
6166 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006167 cc = (int)STRLEN(ml_get_curline());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006168 if (VIsual.col > (colnr_T)cc)
6169 {
6170 VIsual.col = cc;
6171# ifdef FEAT_VIRTUALEDIT
6172 VIsual.coladd = 0;
6173# endif
6174 }
6175 }
6176#endif
6177 }
6178 }
6179 did_ai = FALSE;
6180#ifdef FEAT_SMARTINDENT
6181 did_si = FALSE;
6182 can_si = FALSE;
6183 can_si_back = FALSE;
6184#endif
6185
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006186 /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
6187 * now in a different buffer. */
6188 if (end_insert_pos != NULL)
6189 {
6190 curbuf->b_op_start = Insstart;
6191 curbuf->b_op_end = *end_insert_pos;
6192 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193}
6194
6195/*
6196 * Set the last inserted text to a single character.
6197 * Used for the replace command.
6198 */
6199 void
6200set_last_insert(c)
6201 int c;
6202{
6203 char_u *s;
6204
6205 vim_free(last_insert);
6206#ifdef FEAT_MBYTE
6207 last_insert = alloc(MB_MAXBYTES * 3 + 5);
6208#else
6209 last_insert = alloc(6);
6210#endif
6211 if (last_insert != NULL)
6212 {
6213 s = last_insert;
6214 /* Use the CTRL-V only when entering a special char */
6215 if (c < ' ' || c == DEL)
6216 *s++ = Ctrl_V;
6217 s = add_char2buf(c, s);
6218 *s++ = ESC;
6219 *s++ = NUL;
6220 last_insert_skip = 0;
6221 }
6222}
6223
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006224#if defined(EXITFREE) || defined(PROTO)
6225 void
6226free_last_insert()
6227{
6228 vim_free(last_insert);
6229 last_insert = NULL;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006230 vim_free(compl_orig_text);
6231 compl_orig_text = NULL;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006232}
6233#endif
6234
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235/*
6236 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
6237 * and CSI. Handle multi-byte characters.
6238 * Returns a pointer to after the added bytes.
6239 */
6240 char_u *
6241add_char2buf(c, s)
6242 int c;
6243 char_u *s;
6244{
6245#ifdef FEAT_MBYTE
6246 char_u temp[MB_MAXBYTES];
6247 int i;
6248 int len;
6249
6250 len = (*mb_char2bytes)(c, temp);
6251 for (i = 0; i < len; ++i)
6252 {
6253 c = temp[i];
6254#endif
6255 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
6256 if (c == K_SPECIAL)
6257 {
6258 *s++ = K_SPECIAL;
6259 *s++ = KS_SPECIAL;
6260 *s++ = KE_FILLER;
6261 }
6262#ifdef FEAT_GUI
6263 else if (c == CSI)
6264 {
6265 *s++ = CSI;
6266 *s++ = KS_EXTRA;
6267 *s++ = (int)KE_CSI;
6268 }
6269#endif
6270 else
6271 *s++ = c;
6272#ifdef FEAT_MBYTE
6273 }
6274#endif
6275 return s;
6276}
6277
6278/*
6279 * move cursor to start of line
6280 * if flags & BL_WHITE move to first non-white
6281 * if flags & BL_SOL move to first non-white if startofline is set,
6282 * otherwise keep "curswant" column
6283 * if flags & BL_FIX don't leave the cursor on a NUL.
6284 */
6285 void
6286beginline(flags)
6287 int flags;
6288{
6289 if ((flags & BL_SOL) && !p_sol)
6290 coladvance(curwin->w_curswant);
6291 else
6292 {
6293 curwin->w_cursor.col = 0;
6294#ifdef FEAT_VIRTUALEDIT
6295 curwin->w_cursor.coladd = 0;
6296#endif
6297
6298 if (flags & (BL_WHITE | BL_SOL))
6299 {
6300 char_u *ptr;
6301
6302 for (ptr = ml_get_curline(); vim_iswhite(*ptr)
6303 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
6304 ++curwin->w_cursor.col;
6305 }
6306 curwin->w_set_curswant = TRUE;
6307 }
6308}
6309
6310/*
6311 * oneright oneleft cursor_down cursor_up
6312 *
6313 * Move one char {right,left,down,up}.
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006314 * Doesn't move onto the NUL past the end of the line, unless it is allowed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315 * Return OK when successful, FAIL when we hit a line of file boundary.
6316 */
6317
6318 int
6319oneright()
6320{
6321 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006322 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323
6324#ifdef FEAT_VIRTUALEDIT
6325 if (virtual_active())
6326 {
6327 pos_T prevpos = curwin->w_cursor;
6328
6329 /* Adjust for multi-wide char (excluding TAB) */
6330 ptr = ml_get_cursor();
6331 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006332# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00006333 (*mb_ptr2char)(ptr)
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006334# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335 *ptr
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006336# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006337 ))
6338 ? ptr2cells(ptr) : 1));
6339 curwin->w_set_curswant = TRUE;
6340 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
6341 return (prevpos.col != curwin->w_cursor.col
6342 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
6343 }
6344#endif
6345
6346 ptr = ml_get_cursor();
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006347 if (*ptr == NUL)
6348 return FAIL; /* already at the very end */
6349
Bram Moolenaar071d4272004-06-13 20:20:40 +00006350#ifdef FEAT_MBYTE
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006351 if (has_mbyte)
6352 l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353 else
6354#endif
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00006355 l = 1;
6356
6357 /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
6358 * contains "onemore". */
6359 if (ptr[l] == NUL
6360#ifdef FEAT_VIRTUALEDIT
6361 && (ve_flags & VE_ONEMORE) == 0
6362#endif
6363 )
6364 return FAIL;
6365 curwin->w_cursor.col += l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006366
6367 curwin->w_set_curswant = TRUE;
6368 return OK;
6369}
6370
6371 int
6372oneleft()
6373{
6374#ifdef FEAT_VIRTUALEDIT
6375 if (virtual_active())
6376 {
6377 int width;
6378 int v = getviscol();
6379
6380 if (v == 0)
6381 return FAIL;
6382
6383# ifdef FEAT_LINEBREAK
6384 /* We might get stuck on 'showbreak', skip over it. */
6385 width = 1;
6386 for (;;)
6387 {
6388 coladvance(v - width);
6389 /* getviscol() is slow, skip it when 'showbreak' is empty and
6390 * there are no multi-byte characters */
6391 if ((*p_sbr == NUL
6392# ifdef FEAT_MBYTE
6393 && !has_mbyte
6394# endif
6395 ) || getviscol() < v)
6396 break;
6397 ++width;
6398 }
6399# else
6400 coladvance(v - 1);
6401# endif
6402
6403 if (curwin->w_cursor.coladd == 1)
6404 {
6405 char_u *ptr;
6406
6407 /* Adjust for multi-wide char (not a TAB) */
6408 ptr = ml_get_cursor();
6409 if (*ptr != TAB && vim_isprintc(
6410# ifdef FEAT_MBYTE
6411 (*mb_ptr2char)(ptr)
6412# else
6413 *ptr
6414# endif
6415 ) && ptr2cells(ptr) > 1)
6416 curwin->w_cursor.coladd = 0;
6417 }
6418
6419 curwin->w_set_curswant = TRUE;
6420 return OK;
6421 }
6422#endif
6423
6424 if (curwin->w_cursor.col == 0)
6425 return FAIL;
6426
6427 curwin->w_set_curswant = TRUE;
6428 --curwin->w_cursor.col;
6429
6430#ifdef FEAT_MBYTE
6431 /* if the character on the left of the current cursor is a multi-byte
6432 * character, move to its first byte */
6433 if (has_mbyte)
6434 mb_adjust_cursor();
6435#endif
6436 return OK;
6437}
6438
6439 int
6440cursor_up(n, upd_topline)
6441 long n;
6442 int upd_topline; /* When TRUE: update topline */
6443{
6444 linenr_T lnum;
6445
6446 if (n > 0)
6447 {
6448 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00006449 /* This fails if the cursor is already in the first line or the count
6450 * is larger than the line number and '-' is in 'cpoptions' */
6451 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006452 return FAIL;
6453 if (n >= lnum)
6454 lnum = 1;
6455 else
6456#ifdef FEAT_FOLDING
6457 if (hasAnyFolding(curwin))
6458 {
6459 /*
6460 * Count each sequence of folded lines as one logical line.
6461 */
6462 /* go to the the start of the current fold */
6463 (void)hasFolding(lnum, &lnum, NULL);
6464
6465 while (n--)
6466 {
6467 /* move up one line */
6468 --lnum;
6469 if (lnum <= 1)
6470 break;
6471 /* If we entered a fold, move to the beginning, unless in
6472 * Insert mode or when 'foldopen' contains "all": it will open
6473 * in a moment. */
6474 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
6475 (void)hasFolding(lnum, &lnum, NULL);
6476 }
6477 if (lnum < 1)
6478 lnum = 1;
6479 }
6480 else
6481#endif
6482 lnum -= n;
6483 curwin->w_cursor.lnum = lnum;
6484 }
6485
6486 /* try to advance to the column we want to be at */
6487 coladvance(curwin->w_curswant);
6488
6489 if (upd_topline)
6490 update_topline(); /* make sure curwin->w_topline is valid */
6491
6492 return OK;
6493}
6494
6495/*
6496 * Cursor down a number of logical lines.
6497 */
6498 int
6499cursor_down(n, upd_topline)
6500 long n;
6501 int upd_topline; /* When TRUE: update topline */
6502{
6503 linenr_T lnum;
6504
6505 if (n > 0)
6506 {
6507 lnum = curwin->w_cursor.lnum;
6508#ifdef FEAT_FOLDING
6509 /* Move to last line of fold, will fail if it's the end-of-file. */
6510 (void)hasFolding(lnum, NULL, &lnum);
6511#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00006512 /* This fails if the cursor is already in the last line or would move
6513 * beyound the last line and '-' is in 'cpoptions' */
6514 if (lnum >= curbuf->b_ml.ml_line_count
6515 || (lnum + n > curbuf->b_ml.ml_line_count
6516 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517 return FAIL;
6518 if (lnum + n >= curbuf->b_ml.ml_line_count)
6519 lnum = curbuf->b_ml.ml_line_count;
6520 else
6521#ifdef FEAT_FOLDING
6522 if (hasAnyFolding(curwin))
6523 {
6524 linenr_T last;
6525
6526 /* count each sequence of folded lines as one logical line */
6527 while (n--)
6528 {
6529 if (hasFolding(lnum, NULL, &last))
6530 lnum = last + 1;
6531 else
6532 ++lnum;
6533 if (lnum >= curbuf->b_ml.ml_line_count)
6534 break;
6535 }
6536 if (lnum > curbuf->b_ml.ml_line_count)
6537 lnum = curbuf->b_ml.ml_line_count;
6538 }
6539 else
6540#endif
6541 lnum += n;
6542 curwin->w_cursor.lnum = lnum;
6543 }
6544
6545 /* try to advance to the column we want to be at */
6546 coladvance(curwin->w_curswant);
6547
6548 if (upd_topline)
6549 update_topline(); /* make sure curwin->w_topline is valid */
6550
6551 return OK;
6552}
6553
6554/*
6555 * Stuff the last inserted text in the read buffer.
6556 * Last_insert actually is a copy of the redo buffer, so we
6557 * first have to remove the command.
6558 */
6559 int
6560stuff_inserted(c, count, no_esc)
6561 int c; /* Command character to be inserted */
6562 long count; /* Repeat this many times */
6563 int no_esc; /* Don't add an ESC at the end */
6564{
6565 char_u *esc_ptr;
6566 char_u *ptr;
6567 char_u *last_ptr;
6568 char_u last = NUL;
6569
6570 ptr = get_last_insert();
6571 if (ptr == NULL)
6572 {
6573 EMSG(_(e_noinstext));
6574 return FAIL;
6575 }
6576
6577 /* may want to stuff the command character, to start Insert mode */
6578 if (c != NUL)
6579 stuffcharReadbuff(c);
6580 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
6581 *esc_ptr = NUL; /* remove the ESC */
6582
6583 /* when the last char is either "0" or "^" it will be quoted if no ESC
6584 * comes after it OR if it will inserted more than once and "ptr"
6585 * starts with ^D. -- Acevedo
6586 */
6587 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
6588 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
6589 && (no_esc || (*ptr == Ctrl_D && count > 1)))
6590 {
6591 last = *last_ptr;
6592 *last_ptr = NUL;
6593 }
6594
6595 do
6596 {
6597 stuffReadbuff(ptr);
6598 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
6599 if (last)
6600 stuffReadbuff((char_u *)(last == '0'
6601 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
6602 : IF_EB("\026^", CTRL_V_STR "^")));
6603 }
6604 while (--count > 0);
6605
6606 if (last)
6607 *last_ptr = last;
6608
6609 if (esc_ptr != NULL)
6610 *esc_ptr = ESC; /* put the ESC back */
6611
6612 /* may want to stuff a trailing ESC, to get out of Insert mode */
6613 if (!no_esc)
6614 stuffcharReadbuff(ESC);
6615
6616 return OK;
6617}
6618
6619 char_u *
6620get_last_insert()
6621{
6622 if (last_insert == NULL)
6623 return NULL;
6624 return last_insert + last_insert_skip;
6625}
6626
6627/*
6628 * Get last inserted string, and remove trailing <Esc>.
6629 * Returns pointer to allocated memory (must be freed) or NULL.
6630 */
6631 char_u *
6632get_last_insert_save()
6633{
6634 char_u *s;
6635 int len;
6636
6637 if (last_insert == NULL)
6638 return NULL;
6639 s = vim_strsave(last_insert + last_insert_skip);
6640 if (s != NULL)
6641 {
6642 len = (int)STRLEN(s);
6643 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
6644 s[len - 1] = NUL;
6645 }
6646 return s;
6647}
6648
6649/*
6650 * Check the word in front of the cursor for an abbreviation.
6651 * Called when the non-id character "c" has been entered.
6652 * When an abbreviation is recognized it is removed from the text and
6653 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
6654 */
6655 static int
6656echeck_abbr(c)
6657 int c;
6658{
6659 /* Don't check for abbreviation in paste mode, when disabled and just
6660 * after moving around with cursor keys. */
6661 if (p_paste || no_abbr || arrow_used)
6662 return FALSE;
6663
6664 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
6665 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
6666}
6667
6668/*
6669 * replace-stack functions
6670 *
6671 * When replacing characters, the replaced characters are remembered for each
6672 * new character. This is used to re-insert the old text when backspacing.
6673 *
6674 * There is a NUL headed list of characters for each character that is
6675 * currently in the file after the insertion point. When BS is used, one NUL
6676 * headed list is put back for the deleted character.
6677 *
6678 * For a newline, there are two NUL headed lists. One contains the characters
6679 * that the NL replaced. The extra one stores the characters after the cursor
6680 * that were deleted (always white space).
6681 *
6682 * Replace_offset is normally 0, in which case replace_push will add a new
6683 * character at the end of the stack. If replace_offset is not 0, that many
6684 * characters will be left on the stack above the newly inserted character.
6685 */
6686
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00006687static char_u *replace_stack = NULL;
6688static long replace_stack_nr = 0; /* next entry in replace stack */
6689static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690
6691 void
6692replace_push(c)
6693 int c; /* character that is replaced (NUL is none) */
6694{
6695 char_u *p;
6696
6697 if (replace_stack_nr < replace_offset) /* nothing to do */
6698 return;
6699 if (replace_stack_len <= replace_stack_nr)
6700 {
6701 replace_stack_len += 50;
6702 p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
6703 if (p == NULL) /* out of memory */
6704 {
6705 replace_stack_len -= 50;
6706 return;
6707 }
6708 if (replace_stack != NULL)
6709 {
6710 mch_memmove(p, replace_stack,
6711 (size_t)(replace_stack_nr * sizeof(char_u)));
6712 vim_free(replace_stack);
6713 }
6714 replace_stack = p;
6715 }
6716 p = replace_stack + replace_stack_nr - replace_offset;
6717 if (replace_offset)
6718 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
6719 *p = c;
6720 ++replace_stack_nr;
6721}
6722
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006723#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006724/*
6725 * call replace_push(c) with replace_offset set to the first NUL.
6726 */
6727 static void
6728replace_push_off(c)
6729 int c;
6730{
6731 char_u *p;
6732
6733 p = replace_stack + replace_stack_nr;
6734 for (replace_offset = 1; replace_offset < replace_stack_nr;
6735 ++replace_offset)
6736 if (*--p == NUL)
6737 break;
6738 replace_push(c);
6739 replace_offset = 0;
6740}
Bram Moolenaareb3593b2006-04-22 22:33:57 +00006741#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006742
6743/*
6744 * Pop one item from the replace stack.
6745 * return -1 if stack empty
6746 * return replaced character or NUL otherwise
6747 */
6748 static int
6749replace_pop()
6750{
6751 if (replace_stack_nr == 0)
6752 return -1;
6753 return (int)replace_stack[--replace_stack_nr];
6754}
6755
6756/*
6757 * Join the top two items on the replace stack. This removes to "off"'th NUL
6758 * encountered.
6759 */
6760 static void
6761replace_join(off)
6762 int off; /* offset for which NUL to remove */
6763{
6764 int i;
6765
6766 for (i = replace_stack_nr; --i >= 0; )
6767 if (replace_stack[i] == NUL && off-- <= 0)
6768 {
6769 --replace_stack_nr;
6770 mch_memmove(replace_stack + i, replace_stack + i + 1,
6771 (size_t)(replace_stack_nr - i));
6772 return;
6773 }
6774}
6775
6776/*
6777 * Pop bytes from the replace stack until a NUL is found, and insert them
6778 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
6779 */
6780 static void
6781replace_pop_ins()
6782{
6783 int cc;
6784 int oldState = State;
6785
6786 State = NORMAL; /* don't want REPLACE here */
6787 while ((cc = replace_pop()) > 0)
6788 {
6789#ifdef FEAT_MBYTE
6790 mb_replace_pop_ins(cc);
6791#else
6792 ins_char(cc);
6793#endif
6794 dec_cursor();
6795 }
6796 State = oldState;
6797}
6798
6799#ifdef FEAT_MBYTE
6800/*
6801 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
6802 * indicates a multi-byte char, pop the other bytes too.
6803 */
6804 static void
6805mb_replace_pop_ins(cc)
6806 int cc;
6807{
6808 int n;
6809 char_u buf[MB_MAXBYTES];
6810 int i;
6811 int c;
6812
6813 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
6814 {
6815 buf[0] = cc;
6816 for (i = 1; i < n; ++i)
6817 buf[i] = replace_pop();
6818 ins_bytes_len(buf, n);
6819 }
6820 else
6821 ins_char(cc);
6822
6823 if (enc_utf8)
6824 /* Handle composing chars. */
6825 for (;;)
6826 {
6827 c = replace_pop();
6828 if (c == -1) /* stack empty */
6829 break;
6830 if ((n = MB_BYTE2LEN(c)) == 1)
6831 {
6832 /* Not a multi-byte char, put it back. */
6833 replace_push(c);
6834 break;
6835 }
6836 else
6837 {
6838 buf[0] = c;
6839 for (i = 1; i < n; ++i)
6840 buf[i] = replace_pop();
6841 if (utf_iscomposing(utf_ptr2char(buf)))
6842 ins_bytes_len(buf, n);
6843 else
6844 {
6845 /* Not a composing char, put it back. */
6846 for (i = n - 1; i >= 0; --i)
6847 replace_push(buf[i]);
6848 break;
6849 }
6850 }
6851 }
6852}
6853#endif
6854
6855/*
6856 * make the replace stack empty
6857 * (called when exiting replace mode)
6858 */
6859 static void
6860replace_flush()
6861{
6862 vim_free(replace_stack);
6863 replace_stack = NULL;
6864 replace_stack_len = 0;
6865 replace_stack_nr = 0;
6866}
6867
6868/*
6869 * Handle doing a BS for one character.
6870 * cc < 0: replace stack empty, just move cursor
6871 * cc == 0: character was inserted, delete it
6872 * cc > 0: character was replaced, put cc (first byte of original char) back
6873 * and check for more characters to be put back
6874 */
6875 static void
6876replace_do_bs()
6877{
6878 int cc;
6879#ifdef FEAT_VREPLACE
6880 int orig_len = 0;
6881 int ins_len;
6882 int orig_vcols = 0;
6883 colnr_T start_vcol;
6884 char_u *p;
6885 int i;
6886 int vcol;
6887#endif
6888
6889 cc = replace_pop();
6890 if (cc > 0)
6891 {
6892#ifdef FEAT_VREPLACE
6893 if (State & VREPLACE_FLAG)
6894 {
6895 /* Get the number of screen cells used by the character we are
6896 * going to delete. */
6897 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
6898 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
6899 }
6900#endif
6901#ifdef FEAT_MBYTE
6902 if (has_mbyte)
6903 {
6904 del_char(FALSE);
6905# ifdef FEAT_VREPLACE
6906 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006907 orig_len = (int)STRLEN(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00006908# endif
6909 replace_push(cc);
6910 }
6911 else
6912#endif
6913 {
6914 pchar_cursor(cc);
6915#ifdef FEAT_VREPLACE
6916 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006917 orig_len = (int)STRLEN(ml_get_cursor()) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006918#endif
6919 }
6920 replace_pop_ins();
6921
6922#ifdef FEAT_VREPLACE
6923 if (State & VREPLACE_FLAG)
6924 {
6925 /* Get the number of screen cells used by the inserted characters */
6926 p = ml_get_cursor();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006927 ins_len = (int)STRLEN(p) - orig_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 vcol = start_vcol;
6929 for (i = 0; i < ins_len; ++i)
6930 {
6931 vcol += chartabsize(p + i, vcol);
6932#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006933 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006934#endif
6935 }
6936 vcol -= start_vcol;
6937
6938 /* Delete spaces that were inserted after the cursor to keep the
6939 * text aligned. */
6940 curwin->w_cursor.col += ins_len;
6941 while (vcol > orig_vcols && gchar_cursor() == ' ')
6942 {
6943 del_char(FALSE);
6944 ++orig_vcols;
6945 }
6946 curwin->w_cursor.col -= ins_len;
6947 }
6948#endif
6949
6950 /* mark the buffer as changed and prepare for displaying */
6951 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
6952 }
6953 else if (cc == 0)
6954 (void)del_char(FALSE);
6955}
6956
6957#ifdef FEAT_CINDENT
6958/*
6959 * Return TRUE if C-indenting is on.
6960 */
6961 static int
6962cindent_on()
6963{
6964 return (!p_paste && (curbuf->b_p_cin
6965# ifdef FEAT_EVAL
6966 || *curbuf->b_p_inde != NUL
6967# endif
6968 ));
6969}
6970#endif
6971
6972#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
6973/*
6974 * Re-indent the current line, based on the current contents of it and the
6975 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
6976 * confused what all the part that handles Control-T is doing that I'm not.
6977 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
6978 */
6979
6980 void
6981fixthisline(get_the_indent)
6982 int (*get_the_indent) __ARGS((void));
6983{
6984 change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
6985 if (linewhite(curwin->w_cursor.lnum))
6986 did_ai = TRUE; /* delete the indent if the line stays empty */
6987}
6988
6989 void
6990fix_indent()
6991{
6992 if (p_paste)
6993 return;
6994# ifdef FEAT_LISP
6995 if (curbuf->b_p_lisp && curbuf->b_p_ai)
6996 fixthisline(get_lisp_indent);
6997# endif
6998# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
6999 else
7000# endif
7001# ifdef FEAT_CINDENT
7002 if (cindent_on())
7003 do_c_expr_indent();
7004# endif
7005}
7006
7007#endif
7008
7009#ifdef FEAT_CINDENT
7010/*
7011 * return TRUE if 'cinkeys' contains the key "keytyped",
7012 * when == '*': Only if key is preceded with '*' (indent before insert)
7013 * when == '!': Only if key is prededed with '!' (don't insert)
7014 * when == ' ': Only if key is not preceded with '*'(indent afterwards)
7015 *
7016 * "keytyped" can have a few special values:
7017 * KEY_OPEN_FORW
7018 * KEY_OPEN_BACK
7019 * KEY_COMPLETE just finished completion.
7020 *
7021 * If line_is_empty is TRUE accept keys with '0' before them.
7022 */
7023 int
7024in_cinkeys(keytyped, when, line_is_empty)
7025 int keytyped;
7026 int when;
7027 int line_is_empty;
7028{
7029 char_u *look;
7030 int try_match;
7031 int try_match_word;
7032 char_u *p;
7033 char_u *line;
7034 int icase;
7035 int i;
7036
7037#ifdef FEAT_EVAL
7038 if (*curbuf->b_p_inde != NUL)
7039 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
7040 else
7041#endif
7042 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
7043 while (*look)
7044 {
7045 /*
7046 * Find out if we want to try a match with this key, depending on
7047 * 'when' and a '*' or '!' before the key.
7048 */
7049 switch (when)
7050 {
7051 case '*': try_match = (*look == '*'); break;
7052 case '!': try_match = (*look == '!'); break;
7053 default: try_match = (*look != '*'); break;
7054 }
7055 if (*look == '*' || *look == '!')
7056 ++look;
7057
7058 /*
7059 * If there is a '0', only accept a match if the line is empty.
7060 * But may still match when typing last char of a word.
7061 */
7062 if (*look == '0')
7063 {
7064 try_match_word = try_match;
7065 if (!line_is_empty)
7066 try_match = FALSE;
7067 ++look;
7068 }
7069 else
7070 try_match_word = FALSE;
7071
7072 /*
7073 * does it look like a control character?
7074 */
7075 if (*look == '^'
7076#ifdef EBCDIC
7077 && (Ctrl_chr(look[1]) != 0)
7078#else
7079 && look[1] >= '?' && look[1] <= '_'
7080#endif
7081 )
7082 {
7083 if (try_match && keytyped == Ctrl_chr(look[1]))
7084 return TRUE;
7085 look += 2;
7086 }
7087 /*
7088 * 'o' means "o" command, open forward.
7089 * 'O' means "O" command, open backward.
7090 */
7091 else if (*look == 'o')
7092 {
7093 if (try_match && keytyped == KEY_OPEN_FORW)
7094 return TRUE;
7095 ++look;
7096 }
7097 else if (*look == 'O')
7098 {
7099 if (try_match && keytyped == KEY_OPEN_BACK)
7100 return TRUE;
7101 ++look;
7102 }
7103
7104 /*
7105 * 'e' means to check for "else" at start of line and just before the
7106 * cursor.
7107 */
7108 else if (*look == 'e')
7109 {
7110 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
7111 {
7112 p = ml_get_curline();
7113 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
7114 STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
7115 return TRUE;
7116 }
7117 ++look;
7118 }
7119
7120 /*
7121 * ':' only causes an indent if it is at the end of a label or case
7122 * statement, or when it was before typing the ':' (to fix
7123 * class::method for C++).
7124 */
7125 else if (*look == ':')
7126 {
7127 if (try_match && keytyped == ':')
7128 {
7129 p = ml_get_curline();
7130 if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
7131 return TRUE;
7132 if (curwin->w_cursor.col > 2
7133 && p[curwin->w_cursor.col - 1] == ':'
7134 && p[curwin->w_cursor.col - 2] == ':')
7135 {
7136 p[curwin->w_cursor.col - 1] = ' ';
7137 i = (cin_iscase(p) || cin_isscopedecl(p)
7138 || cin_islabel(30));
7139 p = ml_get_curline();
7140 p[curwin->w_cursor.col - 1] = ':';
7141 if (i)
7142 return TRUE;
7143 }
7144 }
7145 ++look;
7146 }
7147
7148
7149 /*
7150 * Is it a key in <>, maybe?
7151 */
7152 else if (*look == '<')
7153 {
7154 if (try_match)
7155 {
7156 /*
7157 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
7158 * <:> and <!> so that people can re-indent on o, O, e, 0, <,
7159 * >, *, : and ! keys if they really really want to.
7160 */
7161 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
7162 && keytyped == look[1])
7163 return TRUE;
7164
7165 if (keytyped == get_special_key_code(look + 1))
7166 return TRUE;
7167 }
7168 while (*look && *look != '>')
7169 look++;
7170 while (*look == '>')
7171 look++;
7172 }
7173
7174 /*
7175 * Is it a word: "=word"?
7176 */
7177 else if (*look == '=' && look[1] != ',' && look[1] != NUL)
7178 {
7179 ++look;
7180 if (*look == '~')
7181 {
7182 icase = TRUE;
7183 ++look;
7184 }
7185 else
7186 icase = FALSE;
7187 p = vim_strchr(look, ',');
7188 if (p == NULL)
7189 p = look + STRLEN(look);
7190 if ((try_match || try_match_word)
7191 && curwin->w_cursor.col >= (colnr_T)(p - look))
7192 {
7193 int match = FALSE;
7194
7195#ifdef FEAT_INS_EXPAND
7196 if (keytyped == KEY_COMPLETE)
7197 {
7198 char_u *s;
7199
7200 /* Just completed a word, check if it starts with "look".
7201 * search back for the start of a word. */
7202 line = ml_get_curline();
7203# ifdef FEAT_MBYTE
7204 if (has_mbyte)
7205 {
7206 char_u *n;
7207
7208 for (s = line + curwin->w_cursor.col; s > line; s = n)
7209 {
7210 n = mb_prevptr(line, s);
7211 if (!vim_iswordp(n))
7212 break;
7213 }
7214 }
7215 else
7216# endif
7217 for (s = line + curwin->w_cursor.col; s > line; --s)
7218 if (!vim_iswordc(s[-1]))
7219 break;
7220 if (s + (p - look) <= line + curwin->w_cursor.col
7221 && (icase
7222 ? MB_STRNICMP(s, look, p - look)
7223 : STRNCMP(s, look, p - look)) == 0)
7224 match = TRUE;
7225 }
7226 else
7227#endif
7228 /* TODO: multi-byte */
7229 if (keytyped == (int)p[-1] || (icase && keytyped < 256
7230 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
7231 {
7232 line = ml_get_cursor();
7233 if ((curwin->w_cursor.col == (colnr_T)(p - look)
7234 || !vim_iswordc(line[-(p - look) - 1]))
7235 && (icase
7236 ? MB_STRNICMP(line - (p - look), look, p - look)
7237 : STRNCMP(line - (p - look), look, p - look))
7238 == 0)
7239 match = TRUE;
7240 }
7241 if (match && try_match_word && !try_match)
7242 {
7243 /* "0=word": Check if there are only blanks before the
7244 * word. */
7245 line = ml_get_curline();
7246 if ((int)(skipwhite(line) - line) !=
7247 (int)(curwin->w_cursor.col - (p - look)))
7248 match = FALSE;
7249 }
7250 if (match)
7251 return TRUE;
7252 }
7253 look = p;
7254 }
7255
7256 /*
7257 * ok, it's a boring generic character.
7258 */
7259 else
7260 {
7261 if (try_match && *look == keytyped)
7262 return TRUE;
7263 ++look;
7264 }
7265
7266 /*
7267 * Skip over ", ".
7268 */
7269 look = skip_to_option_part(look);
7270 }
7271 return FALSE;
7272}
7273#endif /* FEAT_CINDENT */
7274
7275#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
7276/*
7277 * Map Hebrew keyboard when in hkmap mode.
7278 */
7279 int
7280hkmap(c)
7281 int c;
7282{
7283 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
7284 {
7285 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
7286 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
7287 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
7288 static char_u map[26] =
7289 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
7290 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
7291 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
7292 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
7293 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
7294 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
7295 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
7296 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
7297 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
7298
7299 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
7300 return (int)(map[CharOrd(c)] - 1 + p_aleph);
7301 /* '-1'='sofit' */
7302 else if (c == 'x')
7303 return 'X';
7304 else if (c == 'q')
7305 return '\''; /* {geresh}={'} */
7306 else if (c == 246)
7307 return ' '; /* \"o --> ' ' for a german keyboard */
7308 else if (c == 228)
7309 return ' '; /* \"a --> ' ' -- / -- */
7310 else if (c == 252)
7311 return ' '; /* \"u --> ' ' -- / -- */
7312#ifdef EBCDIC
7313 else if (islower(c))
7314#else
7315 /* NOTE: islower() does not do the right thing for us on Linux so we
7316 * do this the same was as 5.7 and previous, so it works correctly on
7317 * all systems. Specifically, the e.g. Delete and Arrow keys are
7318 * munged and won't work if e.g. searching for Hebrew text.
7319 */
7320 else if (c >= 'a' && c <= 'z')
7321#endif
7322 return (int)(map[CharOrdLow(c)] + p_aleph);
7323 else
7324 return c;
7325 }
7326 else
7327 {
7328 switch (c)
7329 {
7330 case '`': return ';';
7331 case '/': return '.';
7332 case '\'': return ',';
7333 case 'q': return '/';
7334 case 'w': return '\'';
7335
7336 /* Hebrew letters - set offset from 'a' */
7337 case ',': c = '{'; break;
7338 case '.': c = 'v'; break;
7339 case ';': c = 't'; break;
7340 default: {
7341 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
7342
7343#ifdef EBCDIC
7344 /* see note about islower() above */
7345 if (!islower(c))
7346#else
7347 if (c < 'a' || c > 'z')
7348#endif
7349 return c;
7350 c = str[CharOrdLow(c)];
7351 break;
7352 }
7353 }
7354
7355 return (int)(CharOrdLow(c) + p_aleph);
7356 }
7357}
7358#endif
7359
7360 static void
7361ins_reg()
7362{
7363 int need_redraw = FALSE;
7364 int regname;
7365 int literally = 0;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007366#ifdef FEAT_VISUAL
7367 int vis_active = VIsual_active;
7368#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007369
7370 /*
7371 * If we are going to wait for a character, show a '"'.
7372 */
7373 pc_status = PC_STATUS_UNSET;
7374 if (redrawing() && !char_avail())
7375 {
7376 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007377 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007378
7379 edit_putchar('"', TRUE);
7380#ifdef FEAT_CMDL_INFO
7381 add_to_showcmd_c(Ctrl_R);
7382#endif
7383 }
7384
7385#ifdef USE_ON_FLY_SCROLL
7386 dont_scroll = TRUE; /* disallow scrolling here */
7387#endif
7388
7389 /*
7390 * Don't map the register name. This also prevents the mode message to be
7391 * deleted when ESC is hit.
7392 */
7393 ++no_mapping;
7394 regname = safe_vgetc();
7395#ifdef FEAT_LANGMAP
7396 LANGMAP_ADJUST(regname, TRUE);
7397#endif
7398 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
7399 {
7400 /* Get a third key for literal register insertion */
7401 literally = regname;
7402#ifdef FEAT_CMDL_INFO
7403 add_to_showcmd_c(literally);
7404#endif
7405 regname = safe_vgetc();
7406#ifdef FEAT_LANGMAP
7407 LANGMAP_ADJUST(regname, TRUE);
7408#endif
7409 }
7410 --no_mapping;
7411
7412#ifdef FEAT_EVAL
7413 /*
7414 * Don't call u_sync() while getting the expression,
7415 * evaluating it or giving an error message for it!
7416 */
7417 ++no_u_sync;
7418 if (regname == '=')
7419 {
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007420# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007421 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007422# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423 regname = get_expr_register();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007424# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007425 /* Restore the Input Method. */
7426 if (im_on)
7427 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007428# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007429 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00007430 if (regname == NUL || !valid_yank_reg(regname, FALSE))
7431 {
7432 vim_beep();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007433 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00007434 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435 else
7436 {
7437#endif
7438 if (literally == Ctrl_O || literally == Ctrl_P)
7439 {
7440 /* Append the command to the redo buffer. */
7441 AppendCharToRedobuff(Ctrl_R);
7442 AppendCharToRedobuff(literally);
7443 AppendCharToRedobuff(regname);
7444
7445 do_put(regname, BACKWARD, 1L,
7446 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
7447 }
7448 else if (insert_reg(regname, literally) == FAIL)
7449 {
7450 vim_beep();
7451 need_redraw = TRUE; /* remove the '"' */
7452 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00007453 else if (stop_insert_mode)
7454 /* When the '=' register was used and a function was invoked that
7455 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
7456 * insert anything, need to remove the '"' */
7457 need_redraw = TRUE;
7458
Bram Moolenaar071d4272004-06-13 20:20:40 +00007459#ifdef FEAT_EVAL
7460 }
7461 --no_u_sync;
7462#endif
7463#ifdef FEAT_CMDL_INFO
7464 clear_showcmd();
7465#endif
7466
7467 /* If the inserted register is empty, we need to remove the '"' */
7468 if (need_redraw || stuff_empty())
7469 edit_unputchar();
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007470
7471#ifdef FEAT_VISUAL
7472 /* Disallow starting Visual mode here, would get a weird mode. */
7473 if (!vis_active && VIsual_active)
7474 end_visual_mode();
7475#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007476}
7477
7478/*
7479 * CTRL-G commands in Insert mode.
7480 */
7481 static void
7482ins_ctrl_g()
7483{
7484 int c;
7485
7486#ifdef FEAT_INS_EXPAND
7487 /* Right after CTRL-X the cursor will be after the ruler. */
7488 setcursor();
7489#endif
7490
7491 /*
7492 * Don't map the second key. This also prevents the mode message to be
7493 * deleted when ESC is hit.
7494 */
7495 ++no_mapping;
7496 c = safe_vgetc();
7497 --no_mapping;
7498 switch (c)
7499 {
7500 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
7501 case K_UP:
7502 case Ctrl_K:
7503 case 'k': ins_up(TRUE);
7504 break;
7505
7506 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
7507 case K_DOWN:
7508 case Ctrl_J:
7509 case 'j': ins_down(TRUE);
7510 break;
7511
7512 /* CTRL-G u: start new undoable edit */
Bram Moolenaar779b74b2006-04-10 14:55:34 +00007513 case 'u': u_sync(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007514 ins_need_undo = TRUE;
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00007515
7516 /* Need to reset Insstart, esp. because a BS that joins
7517 * aline to the previous one must save for undo. */
7518 Insstart = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007519 break;
7520
7521 /* Unknown CTRL-G command, reserved for future expansion. */
7522 default: vim_beep();
7523 }
7524}
7525
7526/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007527 * CTRL-^ in Insert mode.
7528 */
7529 static void
7530ins_ctrl_hat()
7531{
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00007532 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007533 {
7534 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
7535 if (State & LANGMAP)
7536 {
7537 curbuf->b_p_iminsert = B_IMODE_NONE;
7538 State &= ~LANGMAP;
7539 }
7540 else
7541 {
7542 curbuf->b_p_iminsert = B_IMODE_LMAP;
7543 State |= LANGMAP;
7544#ifdef USE_IM_CONTROL
7545 im_set_active(FALSE);
7546#endif
7547 }
7548 }
7549#ifdef USE_IM_CONTROL
7550 else
7551 {
7552 /* There are no ":lmap" mappings, toggle IM */
7553 if (im_get_status())
7554 {
7555 curbuf->b_p_iminsert = B_IMODE_NONE;
7556 im_set_active(FALSE);
7557 }
7558 else
7559 {
7560 curbuf->b_p_iminsert = B_IMODE_IM;
7561 State &= ~LANGMAP;
7562 im_set_active(TRUE);
7563 }
7564 }
7565#endif
7566 set_iminsert_global();
7567 showmode();
7568#ifdef FEAT_GUI
7569 /* may show different cursor shape or color */
7570 if (gui.in_use)
7571 gui_update_cursor(TRUE, FALSE);
7572#endif
7573#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
7574 /* Show/unshow value of 'keymap' in status lines. */
7575 status_redraw_curbuf();
7576#endif
7577}
7578
7579/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007580 * Handle ESC in insert mode.
7581 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
7582 * insert.
7583 */
7584 static int
Bram Moolenaar488c6512005-08-11 20:09:58 +00007585ins_esc(count, cmdchar, nomove)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007586 long *count;
7587 int cmdchar;
Bram Moolenaar488c6512005-08-11 20:09:58 +00007588 int nomove; /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007589{
7590 int temp;
7591 static int disabled_redraw = FALSE;
7592
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00007593#ifdef FEAT_SPELL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007594 check_spell_redraw();
7595#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007596#if defined(FEAT_HANGULIN)
7597# if defined(ESC_CHG_TO_ENG_MODE)
7598 hangul_input_state_set(0);
7599# endif
7600 if (composing_hangul)
7601 {
7602 push_raw_key(composing_hangul_buffer, 2);
7603 composing_hangul = 0;
7604 }
7605#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007606
7607 temp = curwin->w_cursor.col;
7608 if (disabled_redraw)
7609 {
7610 --RedrawingDisabled;
7611 disabled_redraw = FALSE;
7612 }
7613 if (!arrow_used)
7614 {
7615 /*
7616 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00007617 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
7618 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007619 */
7620 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00007621 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007622
7623 /*
7624 * Repeating insert may take a long time. Check for
7625 * interrupt now and then.
7626 */
7627 if (*count > 0)
7628 {
7629 line_breakcheck();
7630 if (got_int)
7631 *count = 0;
7632 }
7633
7634 if (--*count > 0) /* repeat what was typed */
7635 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00007636 /* Vi repeats the insert without replacing characters. */
7637 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
7638 State &= ~REPLACE_FLAG;
7639
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640 (void)start_redo_ins();
7641 if (cmdchar == 'r' || cmdchar == 'v')
7642 stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
7643 ++RedrawingDisabled;
7644 disabled_redraw = TRUE;
7645 return FALSE; /* repeat the insert */
7646 }
7647 stop_insert(&curwin->w_cursor, TRUE);
7648 undisplay_dollar();
7649 }
7650
7651 /* When an autoindent was removed, curswant stays after the
7652 * indent */
7653 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
7654 curwin->w_set_curswant = TRUE;
7655
7656 /* Remember the last Insert position in the '^ mark. */
7657 if (!cmdmod.keepjumps)
7658 curbuf->b_last_insert = curwin->w_cursor;
7659
7660 /*
7661 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00007662 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007663 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00007664 if (!nomove
7665 && (curwin->w_cursor.col != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007666#ifdef FEAT_VIRTUALEDIT
7667 || curwin->w_cursor.coladd > 0
7668#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007669 )
7670 && (restart_edit == NUL
7671 || (gchar_cursor() == NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007672#ifdef FEAT_VISUAL
Bram Moolenaar488c6512005-08-11 20:09:58 +00007673 && !VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +00007674#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00007675 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007676#ifdef FEAT_RIGHTLEFT
7677 && !revins_on
7678#endif
7679 )
7680 {
7681#ifdef FEAT_VIRTUALEDIT
7682 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
7683 {
7684 oneleft();
7685 if (restart_edit != NUL)
7686 ++curwin->w_cursor.coladd;
7687 }
7688 else
7689#endif
7690 {
7691 --curwin->w_cursor.col;
7692#ifdef FEAT_MBYTE
7693 /* Correct cursor for multi-byte character. */
7694 if (has_mbyte)
7695 mb_adjust_cursor();
7696#endif
7697 }
7698 }
7699
7700#ifdef USE_IM_CONTROL
7701 /* Disable IM to allow typing English directly for Normal mode commands.
7702 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
7703 * well). */
7704 if (!(State & LANGMAP))
7705 im_save_status(&curbuf->b_p_iminsert);
7706 im_set_active(FALSE);
7707#endif
7708
7709 State = NORMAL;
7710 /* need to position cursor again (e.g. when on a TAB ) */
7711 changed_cline_bef_curs();
7712
7713#ifdef FEAT_MOUSE
7714 setmouse();
7715#endif
7716#ifdef CURSOR_SHAPE
7717 ui_cursor_shape(); /* may show different cursor shape */
7718#endif
7719
7720 /*
7721 * When recording or for CTRL-O, need to display the new mode.
7722 * Otherwise remove the mode message.
7723 */
7724 if (Recording || restart_edit != NUL)
7725 showmode();
7726 else if (p_smd)
7727 MSG("");
7728
7729 return TRUE; /* exit Insert mode */
7730}
7731
7732#ifdef FEAT_RIGHTLEFT
7733/*
7734 * Toggle language: hkmap and revins_on.
7735 * Move to end of reverse inserted text.
7736 */
7737 static void
7738ins_ctrl_()
7739{
7740 if (revins_on && revins_chars && revins_scol >= 0)
7741 {
7742 while (gchar_cursor() != NUL && revins_chars--)
7743 ++curwin->w_cursor.col;
7744 }
7745 p_ri = !p_ri;
7746 revins_on = (State == INSERT && p_ri);
7747 if (revins_on)
7748 {
7749 revins_scol = curwin->w_cursor.col;
7750 revins_legal++;
7751 revins_chars = 0;
7752 undisplay_dollar();
7753 }
7754 else
7755 revins_scol = -1;
7756#ifdef FEAT_FKMAP
7757 if (p_altkeymap)
7758 {
7759 /*
7760 * to be consistent also for redo command, using '.'
7761 * set arrow_used to true and stop it - causing to redo
7762 * characters entered in one mode (normal/reverse insert).
7763 */
7764 arrow_used = TRUE;
7765 (void)stop_arrow();
7766 p_fkmap = curwin->w_p_rl ^ p_ri;
7767 if (p_fkmap && p_ri)
7768 State = INSERT;
7769 }
7770 else
7771#endif
7772 p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
7773 showmode();
7774}
7775#endif
7776
7777#ifdef FEAT_VISUAL
7778/*
7779 * If 'keymodel' contains "startsel", may start selection.
7780 * Returns TRUE when a CTRL-O and other keys stuffed.
7781 */
7782 static int
7783ins_start_select(c)
7784 int c;
7785{
7786 if (km_startsel)
7787 switch (c)
7788 {
7789 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007790 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00007791 case K_PAGEUP:
7792 case K_KPAGEUP:
7793 case K_PAGEDOWN:
7794 case K_KPAGEDOWN:
7795# ifdef MACOS
7796 case K_LEFT:
7797 case K_RIGHT:
7798 case K_UP:
7799 case K_DOWN:
7800 case K_END:
7801 case K_HOME:
7802# endif
7803 if (!(mod_mask & MOD_MASK_SHIFT))
7804 break;
7805 /* FALLTHROUGH */
7806 case K_S_LEFT:
7807 case K_S_RIGHT:
7808 case K_S_UP:
7809 case K_S_DOWN:
7810 case K_S_END:
7811 case K_S_HOME:
7812 /* Start selection right away, the cursor can move with
7813 * CTRL-O when beyond the end of the line. */
7814 start_selection();
7815
7816 /* Execute the key in (insert) Select mode. */
7817 stuffcharReadbuff(Ctrl_O);
7818 if (mod_mask)
7819 {
7820 char_u buf[4];
7821
7822 buf[0] = K_SPECIAL;
7823 buf[1] = KS_MODIFIER;
7824 buf[2] = mod_mask;
7825 buf[3] = NUL;
7826 stuffReadbuff(buf);
7827 }
7828 stuffcharReadbuff(c);
7829 return TRUE;
7830 }
7831 return FALSE;
7832}
7833#endif
7834
7835/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007836 * <Insert> key in Insert mode: toggle insert/remplace mode.
7837 */
7838 static void
7839ins_insert(replaceState)
7840 int replaceState;
7841{
7842#ifdef FEAT_FKMAP
7843 if (p_fkmap && p_ri)
7844 {
7845 beep_flush();
7846 EMSG(farsi_text_3); /* encoded in Farsi */
7847 return;
7848 }
7849#endif
7850
7851#ifdef FEAT_AUTOCMD
Bram Moolenaar1e015462005-09-25 22:16:38 +00007852# ifdef FEAT_EVAL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007853 set_vim_var_string(VV_INSERTMODE,
7854 (char_u *)((State & REPLACE_FLAG) ? "i" :
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00007855# ifdef FEAT_VREPLACE
7856 replaceState == VREPLACE ? "v" :
7857# endif
7858 "r"), 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00007859# endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007860 apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
7861#endif
7862 if (State & REPLACE_FLAG)
7863 State = INSERT | (State & LANGMAP);
7864 else
7865 State = replaceState | (State & LANGMAP);
7866 AppendCharToRedobuff(K_INS);
7867 showmode();
7868#ifdef CURSOR_SHAPE
7869 ui_cursor_shape(); /* may show different cursor shape */
7870#endif
7871}
7872
7873/*
7874 * Pressed CTRL-O in Insert mode.
7875 */
7876 static void
7877ins_ctrl_o()
7878{
7879#ifdef FEAT_VREPLACE
7880 if (State & VREPLACE_FLAG)
7881 restart_edit = 'V';
7882 else
7883#endif
7884 if (State & REPLACE_FLAG)
7885 restart_edit = 'R';
7886 else
7887 restart_edit = 'I';
7888#ifdef FEAT_VIRTUALEDIT
7889 if (virtual_active())
7890 ins_at_eol = FALSE; /* cursor always keeps its column */
7891 else
7892#endif
7893 ins_at_eol = (gchar_cursor() == NUL);
7894}
7895
7896/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007897 * If the cursor is on an indent, ^T/^D insert/delete one
7898 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
7899 * Always round the indent to 'shiftwith', this is compatible
7900 * with vi. But vi only supports ^T and ^D after an
7901 * autoindent, we support it everywhere.
7902 */
7903 static void
7904ins_shift(c, lastc)
7905 int c;
7906 int lastc;
7907{
7908 if (stop_arrow() == FAIL)
7909 return;
7910 AppendCharToRedobuff(c);
7911
7912 /*
7913 * 0^D and ^^D: remove all indent.
7914 */
7915 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
7916 {
7917 --curwin->w_cursor.col;
7918 (void)del_char(FALSE); /* delete the '^' or '0' */
7919 /* In Replace mode, restore the characters that '^' or '0' replaced. */
7920 if (State & REPLACE_FLAG)
7921 replace_pop_ins();
7922 if (lastc == '^')
7923 old_indent = get_indent(); /* remember curr. indent */
7924 change_indent(INDENT_SET, 0, TRUE, 0);
7925 }
7926 else
7927 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
7928
7929 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
7930 did_ai = FALSE;
7931#ifdef FEAT_SMARTINDENT
7932 did_si = FALSE;
7933 can_si = FALSE;
7934 can_si_back = FALSE;
7935#endif
7936#ifdef FEAT_CINDENT
7937 can_cindent = FALSE; /* no cindenting after ^D or ^T */
7938#endif
7939}
7940
7941 static void
7942ins_del()
7943{
7944 int temp;
7945
7946 if (stop_arrow() == FAIL)
7947 return;
7948 if (gchar_cursor() == NUL) /* delete newline */
7949 {
7950 temp = curwin->w_cursor.col;
7951 if (!can_bs(BS_EOL) /* only if "eol" included */
7952 || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
7953 (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
7954 || do_join(FALSE) == FAIL)
7955 vim_beep();
7956 else
7957 curwin->w_cursor.col = temp;
7958 }
7959 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
7960 vim_beep();
7961 did_ai = FALSE;
7962#ifdef FEAT_SMARTINDENT
7963 did_si = FALSE;
7964 can_si = FALSE;
7965 can_si_back = FALSE;
7966#endif
7967 AppendCharToRedobuff(K_DEL);
7968}
7969
7970/*
7971 * Handle Backspace, delete-word and delete-line in Insert mode.
7972 * Return TRUE when backspace was actually used.
7973 */
7974 static int
7975ins_bs(c, mode, inserted_space_p)
7976 int c;
7977 int mode;
7978 int *inserted_space_p;
7979{
7980 linenr_T lnum;
7981 int cc;
7982 int temp = 0; /* init for GCC */
7983 colnr_T mincol;
7984 int did_backspace = FALSE;
7985 int in_indent;
7986 int oldState;
7987#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +00007988 int cpc[MAX_MCO]; /* composing characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007989#endif
7990
7991 /*
7992 * can't delete anything in an empty file
7993 * can't backup past first character in buffer
7994 * can't backup past starting point unless 'backspace' > 1
7995 * can backup to a previous line if 'backspace' == 0
7996 */
7997 if ( bufempty()
7998 || (
7999#ifdef FEAT_RIGHTLEFT
8000 !revins_on &&
8001#endif
8002 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
8003 || (!can_bs(BS_START)
8004 && (arrow_used
8005 || (curwin->w_cursor.lnum == Insstart.lnum
8006 && curwin->w_cursor.col <= Insstart.col)))
8007 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
8008 && curwin->w_cursor.col <= ai_col)
8009 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
8010 {
8011 vim_beep();
8012 return FALSE;
8013 }
8014
8015 if (stop_arrow() == FAIL)
8016 return FALSE;
8017 in_indent = inindent(0);
8018#ifdef FEAT_CINDENT
8019 if (in_indent)
8020 can_cindent = FALSE;
8021#endif
8022#ifdef FEAT_COMMENTS
8023 end_comment_pending = NUL; /* After BS, don't auto-end comment */
8024#endif
8025#ifdef FEAT_RIGHTLEFT
8026 if (revins_on) /* put cursor after last inserted char */
8027 inc_cursor();
8028#endif
8029
8030#ifdef FEAT_VIRTUALEDIT
8031 /* Virtualedit:
8032 * BACKSPACE_CHAR eats a virtual space
8033 * BACKSPACE_WORD eats all coladd
8034 * BACKSPACE_LINE eats all coladd and keeps going
8035 */
8036 if (curwin->w_cursor.coladd > 0)
8037 {
8038 if (mode == BACKSPACE_CHAR)
8039 {
8040 --curwin->w_cursor.coladd;
8041 return TRUE;
8042 }
8043 if (mode == BACKSPACE_WORD)
8044 {
8045 curwin->w_cursor.coladd = 0;
8046 return TRUE;
8047 }
8048 curwin->w_cursor.coladd = 0;
8049 }
8050#endif
8051
8052 /*
8053 * delete newline!
8054 */
8055 if (curwin->w_cursor.col == 0)
8056 {
8057 lnum = Insstart.lnum;
8058 if (curwin->w_cursor.lnum == Insstart.lnum
8059#ifdef FEAT_RIGHTLEFT
8060 || revins_on
8061#endif
8062 )
8063 {
8064 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
8065 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
8066 return FALSE;
8067 --Insstart.lnum;
8068 Insstart.col = MAXCOL;
8069 }
8070 /*
8071 * In replace mode:
8072 * cc < 0: NL was inserted, delete it
8073 * cc >= 0: NL was replaced, put original characters back
8074 */
8075 cc = -1;
8076 if (State & REPLACE_FLAG)
8077 cc = replace_pop(); /* returns -1 if NL was inserted */
8078 /*
8079 * In replace mode, in the line we started replacing, we only move the
8080 * cursor.
8081 */
8082 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
8083 {
8084 dec_cursor();
8085 }
8086 else
8087 {
8088#ifdef FEAT_VREPLACE
8089 if (!(State & VREPLACE_FLAG)
8090 || curwin->w_cursor.lnum > orig_line_count)
8091#endif
8092 {
8093 temp = gchar_cursor(); /* remember current char */
8094 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00008095
8096 /* When "aw" is in 'formatoptions' we must delete the space at
8097 * the end of the line, otherwise the line will be broken
8098 * again when auto-formatting. */
8099 if (has_format_option(FO_AUTO)
8100 && has_format_option(FO_WHITE_PAR))
8101 {
8102 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
8103 TRUE);
8104 int len;
8105
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00008106 len = (int)STRLEN(ptr);
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00008107 if (len > 0 && ptr[len - 1] == ' ')
8108 ptr[len - 1] = NUL;
8109 }
8110
Bram Moolenaar071d4272004-06-13 20:20:40 +00008111 (void)do_join(FALSE);
8112 if (temp == NUL && gchar_cursor() != NUL)
8113 inc_cursor();
8114 }
8115#ifdef FEAT_VREPLACE
8116 else
8117 dec_cursor();
8118#endif
8119
8120 /*
8121 * In REPLACE mode we have to put back the text that was replaced
8122 * by the NL. On the replace stack is first a NUL-terminated
8123 * sequence of characters that were deleted and then the
8124 * characters that NL replaced.
8125 */
8126 if (State & REPLACE_FLAG)
8127 {
8128 /*
8129 * Do the next ins_char() in NORMAL state, to
8130 * prevent ins_char() from replacing characters and
8131 * avoiding showmatch().
8132 */
8133 oldState = State;
8134 State = NORMAL;
8135 /*
8136 * restore characters (blanks) deleted after cursor
8137 */
8138 while (cc > 0)
8139 {
8140 temp = curwin->w_cursor.col;
8141#ifdef FEAT_MBYTE
8142 mb_replace_pop_ins(cc);
8143#else
8144 ins_char(cc);
8145#endif
8146 curwin->w_cursor.col = temp;
8147 cc = replace_pop();
8148 }
8149 /* restore the characters that NL replaced */
8150 replace_pop_ins();
8151 State = oldState;
8152 }
8153 }
8154 did_ai = FALSE;
8155 }
8156 else
8157 {
8158 /*
8159 * Delete character(s) before the cursor.
8160 */
8161#ifdef FEAT_RIGHTLEFT
8162 if (revins_on) /* put cursor on last inserted char */
8163 dec_cursor();
8164#endif
8165 mincol = 0;
8166 /* keep indent */
8167 if (mode == BACKSPACE_LINE && curbuf->b_p_ai
8168#ifdef FEAT_RIGHTLEFT
8169 && !revins_on
8170#endif
8171 )
8172 {
8173 temp = curwin->w_cursor.col;
8174 beginline(BL_WHITE);
8175 if (curwin->w_cursor.col < (colnr_T)temp)
8176 mincol = curwin->w_cursor.col;
8177 curwin->w_cursor.col = temp;
8178 }
8179
8180 /*
8181 * Handle deleting one 'shiftwidth' or 'softtabstop'.
8182 */
8183 if ( mode == BACKSPACE_CHAR
8184 && ((p_sta && in_indent)
Bram Moolenaar280f1262006-01-30 00:14:18 +00008185 || (curbuf->b_p_sts != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008186 && (*(ml_get_cursor() - 1) == TAB
8187 || (*(ml_get_cursor() - 1) == ' '
8188 && (!*inserted_space_p
8189 || arrow_used))))))
8190 {
8191 int ts;
8192 colnr_T vcol;
8193 colnr_T want_vcol;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008194#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008195 int extra = 0;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008196#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008197
8198 *inserted_space_p = FALSE;
Bram Moolenaar280f1262006-01-30 00:14:18 +00008199 if (p_sta && in_indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008200 ts = curbuf->b_p_sw;
8201 else
8202 ts = curbuf->b_p_sts;
8203 /* Compute the virtual column where we want to be. Since
8204 * 'showbreak' may get in the way, need to get the last column of
8205 * the previous character. */
8206 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8207 dec_cursor();
8208 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
8209 inc_cursor();
8210 want_vcol = (want_vcol / ts) * ts;
8211
8212 /* delete characters until we are at or before want_vcol */
8213 while (vcol > want_vcol
8214 && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
8215 {
8216 dec_cursor();
8217 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8218 if (State & REPLACE_FLAG)
8219 {
8220 /* Don't delete characters before the insert point when in
8221 * Replace mode */
8222 if (curwin->w_cursor.lnum != Insstart.lnum
8223 || curwin->w_cursor.col >= Insstart.col)
8224 {
8225#if 0 /* what was this for? It causes problems when sw != ts. */
8226 if (State == REPLACE && (int)vcol < want_vcol)
8227 {
8228 (void)del_char(FALSE);
8229 extra = 2; /* don't pop too much */
8230 }
8231 else
8232#endif
8233 replace_do_bs();
8234 }
8235 }
8236 else
8237 (void)del_char(FALSE);
8238 }
8239
8240 /* insert extra spaces until we are at want_vcol */
8241 while (vcol < want_vcol)
8242 {
8243 /* Remember the first char we inserted */
8244 if (curwin->w_cursor.lnum == Insstart.lnum
8245 && curwin->w_cursor.col < Insstart.col)
8246 Insstart.col = curwin->w_cursor.col;
8247
8248#ifdef FEAT_VREPLACE
8249 if (State & VREPLACE_FLAG)
8250 ins_char(' ');
8251 else
8252#endif
8253 {
8254 ins_str((char_u *)" ");
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008255 if ((State & REPLACE_FLAG) /* && extra <= 1 */)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008256 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008257#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008258 if (extra)
8259 replace_push_off(NUL);
8260 else
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008261#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008262 replace_push(NUL);
8263 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008264#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00008265 if (extra == 2)
8266 extra = 1;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008267#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008268 }
8269 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8270 }
8271 }
8272
8273 /*
8274 * Delete upto starting point, start of line or previous word.
8275 */
8276 else do
8277 {
8278#ifdef FEAT_RIGHTLEFT
8279 if (!revins_on) /* put cursor on char to be deleted */
8280#endif
8281 dec_cursor();
8282
8283 /* start of word? */
8284 if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
8285 {
8286 mode = BACKSPACE_WORD_NOT_SPACE;
8287 temp = vim_iswordc(gchar_cursor());
8288 }
8289 /* end of word? */
8290 else if (mode == BACKSPACE_WORD_NOT_SPACE
8291 && (vim_isspace(cc = gchar_cursor())
8292 || vim_iswordc(cc) != temp))
8293 {
8294#ifdef FEAT_RIGHTLEFT
8295 if (!revins_on)
8296#endif
8297 inc_cursor();
8298#ifdef FEAT_RIGHTLEFT
8299 else if (State & REPLACE_FLAG)
8300 dec_cursor();
8301#endif
8302 break;
8303 }
8304 if (State & REPLACE_FLAG)
8305 replace_do_bs();
8306 else
8307 {
8308#ifdef FEAT_MBYTE
8309 if (enc_utf8 && p_deco)
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008310 (void)utfc_ptr2char(ml_get_cursor(), cpc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008311#endif
8312 (void)del_char(FALSE);
8313#ifdef FEAT_MBYTE
8314 /*
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008315 * If there are combining characters and 'delcombine' is set
8316 * move the cursor back. Don't back up before the base
Bram Moolenaar071d4272004-06-13 20:20:40 +00008317 * character.
8318 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00008319 if (enc_utf8 && p_deco && cpc[0] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008320 inc_cursor();
8321#endif
8322#ifdef FEAT_RIGHTLEFT
8323 if (revins_chars)
8324 {
8325 revins_chars--;
8326 revins_legal++;
8327 }
8328 if (revins_on && gchar_cursor() == NUL)
8329 break;
8330#endif
8331 }
8332 /* Just a single backspace?: */
8333 if (mode == BACKSPACE_CHAR)
8334 break;
8335 } while (
8336#ifdef FEAT_RIGHTLEFT
8337 revins_on ||
8338#endif
8339 (curwin->w_cursor.col > mincol
8340 && (curwin->w_cursor.lnum != Insstart.lnum
8341 || curwin->w_cursor.col != Insstart.col)));
8342 did_backspace = TRUE;
8343 }
8344#ifdef FEAT_SMARTINDENT
8345 did_si = FALSE;
8346 can_si = FALSE;
8347 can_si_back = FALSE;
8348#endif
8349 if (curwin->w_cursor.col <= 1)
8350 did_ai = FALSE;
8351 /*
8352 * It's a little strange to put backspaces into the redo
8353 * buffer, but it makes auto-indent a lot easier to deal
8354 * with.
8355 */
8356 AppendCharToRedobuff(c);
8357
8358 /* If deleted before the insertion point, adjust it */
8359 if (curwin->w_cursor.lnum == Insstart.lnum
8360 && curwin->w_cursor.col < Insstart.col)
8361 Insstart.col = curwin->w_cursor.col;
8362
8363 /* vi behaviour: the cursor moves backward but the character that
8364 * was there remains visible
8365 * Vim behaviour: the cursor moves backward and the character that
8366 * was there is erased from the screen.
8367 * We can emulate the vi behaviour by pretending there is a dollar
8368 * displayed even when there isn't.
8369 * --pkv Sun Jan 19 01:56:40 EST 2003 */
8370 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == 0)
8371 dollar_vcol = curwin->w_virtcol;
8372
8373 return did_backspace;
8374}
8375
8376#ifdef FEAT_MOUSE
8377 static void
8378ins_mouse(c)
8379 int c;
8380{
8381 pos_T tpos;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008382 win_T *old_curwin = curwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008383
8384# ifdef FEAT_GUI
8385 /* When GUI is active, also move/paste when 'mouse' is empty */
8386 if (!gui.in_use)
8387# endif
8388 if (!mouse_has(MOUSE_INSERT))
8389 return;
8390
8391 undisplay_dollar();
8392 tpos = curwin->w_cursor;
8393 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
8394 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008395#ifdef FEAT_WINDOWS
8396 win_T *new_curwin = curwin;
8397
8398 if (curwin != old_curwin && win_valid(old_curwin))
8399 {
8400 /* Mouse took us to another window. We need to go back to the
8401 * previous one to stop insert there properly. */
8402 curwin = old_curwin;
8403 curbuf = curwin->w_buffer;
8404 }
8405#endif
8406 start_arrow(curwin == old_curwin ? &tpos : NULL);
8407#ifdef FEAT_WINDOWS
8408 if (curwin != new_curwin && win_valid(new_curwin))
8409 {
8410 curwin = new_curwin;
8411 curbuf = curwin->w_buffer;
8412 }
8413#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008414# ifdef FEAT_CINDENT
8415 can_cindent = TRUE;
8416# endif
8417 }
8418
8419#ifdef FEAT_WINDOWS
8420 /* redraw status lines (in case another window became active) */
8421 redraw_statuslines();
8422#endif
8423}
8424
8425 static void
8426ins_mousescroll(up)
8427 int up;
8428{
8429 pos_T tpos;
8430# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8431 win_T *old_curwin;
8432# endif
8433
8434 tpos = curwin->w_cursor;
8435
8436# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8437 old_curwin = curwin;
8438
8439 /* Currently the mouse coordinates are only known in the GUI. */
8440 if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
8441 {
8442 int row, col;
8443
8444 row = mouse_row;
8445 col = mouse_col;
8446
8447 /* find the window at the pointer coordinates */
8448 curwin = mouse_find_win(&row, &col);
8449 curbuf = curwin->w_buffer;
8450 }
8451 if (curwin == old_curwin)
8452# endif
8453 undisplay_dollar();
8454
8455 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
8456 scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
8457 else
8458 scroll_redraw(up, 3L);
8459
8460# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
8461 curwin->w_redr_status = TRUE;
8462
8463 curwin = old_curwin;
8464 curbuf = curwin->w_buffer;
8465# endif
8466
8467 if (!equalpos(curwin->w_cursor, tpos))
8468 {
8469 start_arrow(&tpos);
8470# ifdef FEAT_CINDENT
8471 can_cindent = TRUE;
8472# endif
8473 }
8474}
8475#endif
8476
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008477#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00008478 static void
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008479ins_tabline(c)
8480 int c;
8481{
8482 /* We will be leaving the current window, unless closing another tab. */
8483 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE
8484 || (current_tab != 0 && current_tab != tabpage_index(curtab)))
8485 {
8486 undisplay_dollar();
8487 start_arrow(&curwin->w_cursor);
8488# ifdef FEAT_CINDENT
8489 can_cindent = TRUE;
8490# endif
8491 }
8492
8493 if (c == K_TABLINE)
8494 goto_tabpage(current_tab);
8495 else
Bram Moolenaar437df8f2006-04-27 21:47:44 +00008496 {
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008497 handle_tabmenu();
Bram Moolenaar437df8f2006-04-27 21:47:44 +00008498 redraw_statuslines(); /* will redraw the tabline when needed */
8499 }
Bram Moolenaara23ccb82006-02-27 00:08:02 +00008500}
8501#endif
8502
8503#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008504 void
8505ins_scroll()
8506{
8507 pos_T tpos;
8508
8509 undisplay_dollar();
8510 tpos = curwin->w_cursor;
8511 if (gui_do_scroll())
8512 {
8513 start_arrow(&tpos);
8514# ifdef FEAT_CINDENT
8515 can_cindent = TRUE;
8516# endif
8517 }
8518}
8519
8520 void
8521ins_horscroll()
8522{
8523 pos_T tpos;
8524
8525 undisplay_dollar();
8526 tpos = curwin->w_cursor;
8527 if (gui_do_horiz_scroll())
8528 {
8529 start_arrow(&tpos);
8530# ifdef FEAT_CINDENT
8531 can_cindent = TRUE;
8532# endif
8533 }
8534}
8535#endif
8536
8537 static void
8538ins_left()
8539{
8540 pos_T tpos;
8541
8542#ifdef FEAT_FOLDING
8543 if ((fdo_flags & FDO_HOR) && KeyTyped)
8544 foldOpenCursor();
8545#endif
8546 undisplay_dollar();
8547 tpos = curwin->w_cursor;
8548 if (oneleft() == OK)
8549 {
8550 start_arrow(&tpos);
8551#ifdef FEAT_RIGHTLEFT
8552 /* If exit reversed string, position is fixed */
8553 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
8554 revins_legal++;
8555 revins_chars++;
8556#endif
8557 }
8558
8559 /*
8560 * if 'whichwrap' set for cursor in insert mode may go to
8561 * previous line
8562 */
8563 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
8564 {
8565 start_arrow(&tpos);
8566 --(curwin->w_cursor.lnum);
8567 coladvance((colnr_T)MAXCOL);
8568 curwin->w_set_curswant = TRUE; /* so we stay at the end */
8569 }
8570 else
8571 vim_beep();
8572}
8573
8574 static void
8575ins_home(c)
8576 int c;
8577{
8578 pos_T tpos;
8579
8580#ifdef FEAT_FOLDING
8581 if ((fdo_flags & FDO_HOR) && KeyTyped)
8582 foldOpenCursor();
8583#endif
8584 undisplay_dollar();
8585 tpos = curwin->w_cursor;
8586 if (c == K_C_HOME)
8587 curwin->w_cursor.lnum = 1;
8588 curwin->w_cursor.col = 0;
8589#ifdef FEAT_VIRTUALEDIT
8590 curwin->w_cursor.coladd = 0;
8591#endif
8592 curwin->w_curswant = 0;
8593 start_arrow(&tpos);
8594}
8595
8596 static void
8597ins_end(c)
8598 int c;
8599{
8600 pos_T tpos;
8601
8602#ifdef FEAT_FOLDING
8603 if ((fdo_flags & FDO_HOR) && KeyTyped)
8604 foldOpenCursor();
8605#endif
8606 undisplay_dollar();
8607 tpos = curwin->w_cursor;
8608 if (c == K_C_END)
8609 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
8610 coladvance((colnr_T)MAXCOL);
8611 curwin->w_curswant = MAXCOL;
8612
8613 start_arrow(&tpos);
8614}
8615
8616 static void
8617ins_s_left()
8618{
8619#ifdef FEAT_FOLDING
8620 if ((fdo_flags & FDO_HOR) && KeyTyped)
8621 foldOpenCursor();
8622#endif
8623 undisplay_dollar();
8624 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
8625 {
8626 start_arrow(&curwin->w_cursor);
8627 (void)bck_word(1L, FALSE, FALSE);
8628 curwin->w_set_curswant = TRUE;
8629 }
8630 else
8631 vim_beep();
8632}
8633
8634 static void
8635ins_right()
8636{
8637#ifdef FEAT_FOLDING
8638 if ((fdo_flags & FDO_HOR) && KeyTyped)
8639 foldOpenCursor();
8640#endif
8641 undisplay_dollar();
8642 if (gchar_cursor() != NUL || virtual_active()
8643 )
8644 {
8645 start_arrow(&curwin->w_cursor);
8646 curwin->w_set_curswant = TRUE;
8647#ifdef FEAT_VIRTUALEDIT
8648 if (virtual_active())
8649 oneright();
8650 else
8651#endif
8652 {
8653#ifdef FEAT_MBYTE
8654 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00008655 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00008656 else
8657#endif
8658 ++curwin->w_cursor.col;
8659 }
8660
8661#ifdef FEAT_RIGHTLEFT
8662 revins_legal++;
8663 if (revins_chars)
8664 revins_chars--;
8665#endif
8666 }
8667 /* if 'whichwrap' set for cursor in insert mode, may move the
8668 * cursor to the next line */
8669 else if (vim_strchr(p_ww, ']') != NULL
8670 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
8671 {
8672 start_arrow(&curwin->w_cursor);
8673 curwin->w_set_curswant = TRUE;
8674 ++curwin->w_cursor.lnum;
8675 curwin->w_cursor.col = 0;
8676 }
8677 else
8678 vim_beep();
8679}
8680
8681 static void
8682ins_s_right()
8683{
8684#ifdef FEAT_FOLDING
8685 if ((fdo_flags & FDO_HOR) && KeyTyped)
8686 foldOpenCursor();
8687#endif
8688 undisplay_dollar();
8689 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
8690 || gchar_cursor() != NUL)
8691 {
8692 start_arrow(&curwin->w_cursor);
8693 (void)fwd_word(1L, FALSE, 0);
8694 curwin->w_set_curswant = TRUE;
8695 }
8696 else
8697 vim_beep();
8698}
8699
8700 static void
8701ins_up(startcol)
8702 int startcol; /* when TRUE move to Insstart.col */
8703{
8704 pos_T tpos;
8705 linenr_T old_topline = curwin->w_topline;
8706#ifdef FEAT_DIFF
8707 int old_topfill = curwin->w_topfill;
8708#endif
8709
8710 undisplay_dollar();
8711 tpos = curwin->w_cursor;
8712 if (cursor_up(1L, TRUE) == OK)
8713 {
8714 if (startcol)
8715 coladvance(getvcol_nolist(&Insstart));
8716 if (old_topline != curwin->w_topline
8717#ifdef FEAT_DIFF
8718 || old_topfill != curwin->w_topfill
8719#endif
8720 )
8721 redraw_later(VALID);
8722 start_arrow(&tpos);
8723#ifdef FEAT_CINDENT
8724 can_cindent = TRUE;
8725#endif
8726 }
8727 else
8728 vim_beep();
8729}
8730
8731 static void
8732ins_pageup()
8733{
8734 pos_T tpos;
8735
8736 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008737
8738#ifdef FEAT_WINDOWS
8739 if (mod_mask & MOD_MASK_CTRL)
8740 {
8741 /* <C-PageUp>: tab page back */
8742 goto_tabpage(-1);
8743 return;
8744 }
8745#endif
8746
Bram Moolenaar071d4272004-06-13 20:20:40 +00008747 tpos = curwin->w_cursor;
8748 if (onepage(BACKWARD, 1L) == OK)
8749 {
8750 start_arrow(&tpos);
8751#ifdef FEAT_CINDENT
8752 can_cindent = TRUE;
8753#endif
8754 }
8755 else
8756 vim_beep();
8757}
8758
8759 static void
8760ins_down(startcol)
8761 int startcol; /* when TRUE move to Insstart.col */
8762{
8763 pos_T tpos;
8764 linenr_T old_topline = curwin->w_topline;
8765#ifdef FEAT_DIFF
8766 int old_topfill = curwin->w_topfill;
8767#endif
8768
8769 undisplay_dollar();
8770 tpos = curwin->w_cursor;
8771 if (cursor_down(1L, TRUE) == OK)
8772 {
8773 if (startcol)
8774 coladvance(getvcol_nolist(&Insstart));
8775 if (old_topline != curwin->w_topline
8776#ifdef FEAT_DIFF
8777 || old_topfill != curwin->w_topfill
8778#endif
8779 )
8780 redraw_later(VALID);
8781 start_arrow(&tpos);
8782#ifdef FEAT_CINDENT
8783 can_cindent = TRUE;
8784#endif
8785 }
8786 else
8787 vim_beep();
8788}
8789
8790 static void
8791ins_pagedown()
8792{
8793 pos_T tpos;
8794
8795 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00008796
8797#ifdef FEAT_WINDOWS
8798 if (mod_mask & MOD_MASK_CTRL)
8799 {
8800 /* <C-PageDown>: tab page forward */
8801 goto_tabpage(0);
8802 return;
8803 }
8804#endif
8805
Bram Moolenaar071d4272004-06-13 20:20:40 +00008806 tpos = curwin->w_cursor;
8807 if (onepage(FORWARD, 1L) == OK)
8808 {
8809 start_arrow(&tpos);
8810#ifdef FEAT_CINDENT
8811 can_cindent = TRUE;
8812#endif
8813 }
8814 else
8815 vim_beep();
8816}
8817
8818#ifdef FEAT_DND
8819 static void
8820ins_drop()
8821{
8822 do_put('~', BACKWARD, 1L, PUT_CURSEND);
8823}
8824#endif
8825
8826/*
8827 * Handle TAB in Insert or Replace mode.
8828 * Return TRUE when the TAB needs to be inserted like a normal character.
8829 */
8830 static int
8831ins_tab()
8832{
8833 int ind;
8834 int i;
8835 int temp;
8836
8837 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
8838 Insstart_blank_vcol = get_nolist_virtcol();
8839 if (echeck_abbr(TAB + ABBR_OFF))
8840 return FALSE;
8841
8842 ind = inindent(0);
8843#ifdef FEAT_CINDENT
8844 if (ind)
8845 can_cindent = FALSE;
8846#endif
8847
8848 /*
8849 * When nothing special, insert TAB like a normal character
8850 */
8851 if (!curbuf->b_p_et
8852 && !(p_sta && ind && curbuf->b_p_ts != curbuf->b_p_sw)
8853 && curbuf->b_p_sts == 0)
8854 return TRUE;
8855
8856 if (stop_arrow() == FAIL)
8857 return TRUE;
8858
8859 did_ai = FALSE;
8860#ifdef FEAT_SMARTINDENT
8861 did_si = FALSE;
8862 can_si = FALSE;
8863 can_si_back = FALSE;
8864#endif
8865 AppendToRedobuff((char_u *)"\t");
8866
8867 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
8868 temp = (int)curbuf->b_p_sw;
8869 else if (curbuf->b_p_sts > 0) /* use 'softtabstop' when set */
8870 temp = (int)curbuf->b_p_sts;
8871 else /* otherwise use 'tabstop' */
8872 temp = (int)curbuf->b_p_ts;
8873 temp -= get_nolist_virtcol() % temp;
8874
8875 /*
8876 * Insert the first space with ins_char(). It will delete one char in
8877 * replace mode. Insert the rest with ins_str(); it will not delete any
8878 * chars. For VREPLACE mode, we use ins_char() for all characters.
8879 */
8880 ins_char(' ');
8881 while (--temp > 0)
8882 {
8883#ifdef FEAT_VREPLACE
8884 if (State & VREPLACE_FLAG)
8885 ins_char(' ');
8886 else
8887#endif
8888 {
8889 ins_str((char_u *)" ");
8890 if (State & REPLACE_FLAG) /* no char replaced */
8891 replace_push(NUL);
8892 }
8893 }
8894
8895 /*
8896 * When 'expandtab' not set: Replace spaces by TABs where possible.
8897 */
8898 if (!curbuf->b_p_et && (curbuf->b_p_sts || (p_sta && ind)))
8899 {
8900 char_u *ptr;
8901#ifdef FEAT_VREPLACE
8902 char_u *saved_line = NULL; /* init for GCC */
8903 pos_T pos;
8904#endif
8905 pos_T fpos;
8906 pos_T *cursor;
8907 colnr_T want_vcol, vcol;
8908 int change_col = -1;
8909 int save_list = curwin->w_p_list;
8910
8911 /*
8912 * Get the current line. For VREPLACE mode, don't make real changes
8913 * yet, just work on a copy of the line.
8914 */
8915#ifdef FEAT_VREPLACE
8916 if (State & VREPLACE_FLAG)
8917 {
8918 pos = curwin->w_cursor;
8919 cursor = &pos;
8920 saved_line = vim_strsave(ml_get_curline());
8921 if (saved_line == NULL)
8922 return FALSE;
8923 ptr = saved_line + pos.col;
8924 }
8925 else
8926#endif
8927 {
8928 ptr = ml_get_cursor();
8929 cursor = &curwin->w_cursor;
8930 }
8931
8932 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
8933 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8934 curwin->w_p_list = FALSE;
8935
8936 /* Find first white before the cursor */
8937 fpos = curwin->w_cursor;
8938 while (fpos.col > 0 && vim_iswhite(ptr[-1]))
8939 {
8940 --fpos.col;
8941 --ptr;
8942 }
8943
8944 /* In Replace mode, don't change characters before the insert point. */
8945 if ((State & REPLACE_FLAG)
8946 && fpos.lnum == Insstart.lnum
8947 && fpos.col < Insstart.col)
8948 {
8949 ptr += Insstart.col - fpos.col;
8950 fpos.col = Insstart.col;
8951 }
8952
8953 /* compute virtual column numbers of first white and cursor */
8954 getvcol(curwin, &fpos, &vcol, NULL, NULL);
8955 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
8956
8957 /* Use as many TABs as possible. Beware of 'showbreak' and
8958 * 'linebreak' adding extra virtual columns. */
8959 while (vim_iswhite(*ptr))
8960 {
8961 i = lbr_chartabsize((char_u *)"\t", vcol);
8962 if (vcol + i > want_vcol)
8963 break;
8964 if (*ptr != TAB)
8965 {
8966 *ptr = TAB;
8967 if (change_col < 0)
8968 {
8969 change_col = fpos.col; /* Column of first change */
8970 /* May have to adjust Insstart */
8971 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
8972 Insstart.col = fpos.col;
8973 }
8974 }
8975 ++fpos.col;
8976 ++ptr;
8977 vcol += i;
8978 }
8979
8980 if (change_col >= 0)
8981 {
8982 int repl_off = 0;
8983
8984 /* Skip over the spaces we need. */
8985 while (vcol < want_vcol && *ptr == ' ')
8986 {
8987 vcol += lbr_chartabsize(ptr, vcol);
8988 ++ptr;
8989 ++repl_off;
8990 }
8991 if (vcol > want_vcol)
8992 {
8993 /* Must have a char with 'showbreak' just before it. */
8994 --ptr;
8995 --repl_off;
8996 }
8997 fpos.col += repl_off;
8998
8999 /* Delete following spaces. */
9000 i = cursor->col - fpos.col;
9001 if (i > 0)
9002 {
9003 mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
9004 /* correct replace stack. */
9005 if ((State & REPLACE_FLAG)
9006#ifdef FEAT_VREPLACE
9007 && !(State & VREPLACE_FLAG)
9008#endif
9009 )
9010 for (temp = i; --temp >= 0; )
9011 replace_join(repl_off);
9012 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00009013#ifdef FEAT_NETBEANS_INTG
9014 if (usingNetbeans)
9015 {
9016 netbeans_removed(curbuf, fpos.lnum, cursor->col,
9017 (long)(i + 1));
9018 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
9019 (char_u *)"\t", 1);
9020 }
9021#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009022 cursor->col -= i;
9023
9024#ifdef FEAT_VREPLACE
9025 /*
9026 * In VREPLACE mode, we haven't changed anything yet. Do it now by
9027 * backspacing over the changed spacing and then inserting the new
9028 * spacing.
9029 */
9030 if (State & VREPLACE_FLAG)
9031 {
9032 /* Backspace from real cursor to change_col */
9033 backspace_until_column(change_col);
9034
9035 /* Insert each char in saved_line from changed_col to
9036 * ptr-cursor */
9037 ins_bytes_len(saved_line + change_col,
9038 cursor->col - change_col);
9039 }
9040#endif
9041 }
9042
9043#ifdef FEAT_VREPLACE
9044 if (State & VREPLACE_FLAG)
9045 vim_free(saved_line);
9046#endif
9047 curwin->w_p_list = save_list;
9048 }
9049
9050 return FALSE;
9051}
9052
9053/*
9054 * Handle CR or NL in insert mode.
9055 * Return TRUE when out of memory or can't undo.
9056 */
9057 static int
9058ins_eol(c)
9059 int c;
9060{
9061 int i;
9062
9063 if (echeck_abbr(c + ABBR_OFF))
9064 return FALSE;
9065 if (stop_arrow() == FAIL)
9066 return TRUE;
9067 undisplay_dollar();
9068
9069 /*
9070 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
9071 * character under the cursor. Only push a NUL on the replace stack,
9072 * nothing to put back when the NL is deleted.
9073 */
9074 if ((State & REPLACE_FLAG)
9075#ifdef FEAT_VREPLACE
9076 && !(State & VREPLACE_FLAG)
9077#endif
9078 )
9079 replace_push(NUL);
9080
9081 /*
9082 * In VREPLACE mode, a NL replaces the rest of the line, and starts
9083 * replacing the next line, so we push all of the characters left on the
9084 * line onto the replace stack. This is not done here though, it is done
9085 * in open_line().
9086 */
9087
Bram Moolenaarf193fff2006-04-27 00:02:13 +00009088#ifdef FEAT_VIRTUALEDIT
9089 /* Put cursor on NUL if on the last char and coladd is 1 (happens after
9090 * CTRL-O). */
9091 if (virtual_active() && curwin->w_cursor.coladd > 0)
9092 coladvance(getviscol());
9093#endif
9094
Bram Moolenaar071d4272004-06-13 20:20:40 +00009095#ifdef FEAT_RIGHTLEFT
9096# ifdef FEAT_FKMAP
9097 if (p_altkeymap && p_fkmap)
9098 fkmap(NL);
9099# endif
9100 /* NL in reverse insert will always start in the end of
9101 * current line. */
9102 if (revins_on)
9103 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
9104#endif
9105
9106 AppendToRedobuff(NL_STR);
9107 i = open_line(FORWARD,
9108#ifdef FEAT_COMMENTS
9109 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
9110#endif
9111 0, old_indent);
9112 old_indent = 0;
9113#ifdef FEAT_CINDENT
9114 can_cindent = TRUE;
9115#endif
9116
9117 return (!i);
9118}
9119
9120#ifdef FEAT_DIGRAPHS
9121/*
9122 * Handle digraph in insert mode.
9123 * Returns character still to be inserted, or NUL when nothing remaining to be
9124 * done.
9125 */
9126 static int
9127ins_digraph()
9128{
9129 int c;
9130 int cc;
9131
9132 pc_status = PC_STATUS_UNSET;
9133 if (redrawing() && !char_avail())
9134 {
9135 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00009136 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009137
9138 edit_putchar('?', TRUE);
9139#ifdef FEAT_CMDL_INFO
9140 add_to_showcmd_c(Ctrl_K);
9141#endif
9142 }
9143
9144#ifdef USE_ON_FLY_SCROLL
9145 dont_scroll = TRUE; /* disallow scrolling here */
9146#endif
9147
9148 /* don't map the digraph chars. This also prevents the
9149 * mode message to be deleted when ESC is hit */
9150 ++no_mapping;
9151 ++allow_keys;
9152 c = safe_vgetc();
9153 --no_mapping;
9154 --allow_keys;
9155 if (IS_SPECIAL(c) || mod_mask) /* special key */
9156 {
9157#ifdef FEAT_CMDL_INFO
9158 clear_showcmd();
9159#endif
9160 insert_special(c, TRUE, FALSE);
9161 return NUL;
9162 }
9163 if (c != ESC)
9164 {
9165 if (redrawing() && !char_avail())
9166 {
9167 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00009168 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009169
9170 if (char2cells(c) == 1)
9171 {
9172 /* first remove the '?', otherwise it's restored when typing
9173 * an ESC next */
9174 edit_unputchar();
Bram Moolenaar754b5602006-02-09 23:53:20 +00009175 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009176 edit_putchar(c, TRUE);
9177 }
9178#ifdef FEAT_CMDL_INFO
9179 add_to_showcmd_c(c);
9180#endif
9181 }
9182 ++no_mapping;
9183 ++allow_keys;
9184 cc = safe_vgetc();
9185 --no_mapping;
9186 --allow_keys;
9187 if (cc != ESC)
9188 {
9189 AppendToRedobuff((char_u *)CTRL_V_STR);
9190 c = getdigraph(c, cc, TRUE);
9191#ifdef FEAT_CMDL_INFO
9192 clear_showcmd();
9193#endif
9194 return c;
9195 }
9196 }
9197 edit_unputchar();
9198#ifdef FEAT_CMDL_INFO
9199 clear_showcmd();
9200#endif
9201 return NUL;
9202}
9203#endif
9204
9205/*
9206 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
9207 * Returns the char to be inserted, or NUL if none found.
9208 */
9209 static int
9210ins_copychar(lnum)
9211 linenr_T lnum;
9212{
9213 int c;
9214 int temp;
9215 char_u *ptr, *prev_ptr;
9216
9217 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
9218 {
9219 vim_beep();
9220 return NUL;
9221 }
9222
9223 /* try to advance to the cursor column */
9224 temp = 0;
9225 ptr = ml_get(lnum);
9226 prev_ptr = ptr;
9227 validate_virtcol();
9228 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
9229 {
9230 prev_ptr = ptr;
9231 temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
9232 }
9233 if ((colnr_T)temp > curwin->w_virtcol)
9234 ptr = prev_ptr;
9235
9236#ifdef FEAT_MBYTE
9237 c = (*mb_ptr2char)(ptr);
9238#else
9239 c = *ptr;
9240#endif
9241 if (c == NUL)
9242 vim_beep();
9243 return c;
9244}
9245
Bram Moolenaar4be06f92005-07-29 22:36:03 +00009246/*
9247 * CTRL-Y or CTRL-E typed in Insert mode.
9248 */
9249 static int
9250ins_ctrl_ey(tc)
9251 int tc;
9252{
9253 int c = tc;
9254
9255#ifdef FEAT_INS_EXPAND
9256 if (ctrl_x_mode == CTRL_X_SCROLL)
9257 {
9258 if (c == Ctrl_Y)
9259 scrolldown_clamp();
9260 else
9261 scrollup_clamp();
9262 redraw_later(VALID);
9263 }
9264 else
9265#endif
9266 {
9267 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
9268 if (c != NUL)
9269 {
9270 long tw_save;
9271
9272 /* The character must be taken literally, insert like it
9273 * was typed after a CTRL-V, and pretend 'textwidth'
9274 * wasn't set. Digits, 'o' and 'x' are special after a
9275 * CTRL-V, don't use it for these. */
9276 if (c < 256 && !isalnum(c))
9277 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
9278 tw_save = curbuf->b_p_tw;
9279 curbuf->b_p_tw = -1;
9280 insert_special(c, TRUE, FALSE);
9281 curbuf->b_p_tw = tw_save;
9282#ifdef FEAT_RIGHTLEFT
9283 revins_chars++;
9284 revins_legal++;
9285#endif
9286 c = Ctrl_V; /* pretend CTRL-V is last character */
9287 auto_format(FALSE, TRUE);
9288 }
9289 }
9290 return c;
9291}
9292
Bram Moolenaar071d4272004-06-13 20:20:40 +00009293#ifdef FEAT_SMARTINDENT
9294/*
9295 * Try to do some very smart auto-indenting.
9296 * Used when inserting a "normal" character.
9297 */
9298 static void
9299ins_try_si(c)
9300 int c;
9301{
9302 pos_T *pos, old_pos;
9303 char_u *ptr;
9304 int i;
9305 int temp;
9306
9307 /*
9308 * do some very smart indenting when entering '{' or '}'
9309 */
9310 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
9311 {
9312 /*
9313 * for '}' set indent equal to indent of line containing matching '{'
9314 */
9315 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
9316 {
9317 old_pos = curwin->w_cursor;
9318 /*
9319 * If the matching '{' has a ')' immediately before it (ignoring
9320 * white-space), then line up with the start of the line
9321 * containing the matching '(' if there is one. This handles the
9322 * case where an "if (..\n..) {" statement continues over multiple
9323 * lines -- webb
9324 */
9325 ptr = ml_get(pos->lnum);
9326 i = pos->col;
9327 if (i > 0) /* skip blanks before '{' */
9328 while (--i > 0 && vim_iswhite(ptr[i]))
9329 ;
9330 curwin->w_cursor.lnum = pos->lnum;
9331 curwin->w_cursor.col = i;
9332 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
9333 curwin->w_cursor = *pos;
9334 i = get_indent();
9335 curwin->w_cursor = old_pos;
9336#ifdef FEAT_VREPLACE
9337 if (State & VREPLACE_FLAG)
9338 change_indent(INDENT_SET, i, FALSE, NUL);
9339 else
9340#endif
9341 (void)set_indent(i, SIN_CHANGED);
9342 }
9343 else if (curwin->w_cursor.col > 0)
9344 {
9345 /*
9346 * when inserting '{' after "O" reduce indent, but not
9347 * more than indent of previous line
9348 */
9349 temp = TRUE;
9350 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
9351 {
9352 old_pos = curwin->w_cursor;
9353 i = get_indent();
9354 while (curwin->w_cursor.lnum > 1)
9355 {
9356 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
9357
9358 /* ignore empty lines and lines starting with '#'. */
9359 if (*ptr != '#' && *ptr != NUL)
9360 break;
9361 }
9362 if (get_indent() >= i)
9363 temp = FALSE;
9364 curwin->w_cursor = old_pos;
9365 }
9366 if (temp)
9367 shift_line(TRUE, FALSE, 1);
9368 }
9369 }
9370
9371 /*
9372 * set indent of '#' always to 0
9373 */
9374 if (curwin->w_cursor.col > 0 && can_si && c == '#')
9375 {
9376 /* remember current indent for next line */
9377 old_indent = get_indent();
9378 (void)set_indent(0, SIN_CHANGED);
9379 }
9380
9381 /* Adjust ai_col, the char at this position can be deleted. */
9382 if (ai_col > curwin->w_cursor.col)
9383 ai_col = curwin->w_cursor.col;
9384}
9385#endif
9386
9387/*
9388 * Get the value that w_virtcol would have when 'list' is off.
9389 * Unless 'cpo' contains the 'L' flag.
9390 */
9391 static colnr_T
9392get_nolist_virtcol()
9393{
9394 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
9395 return getvcol_nolist(&curwin->w_cursor);
9396 validate_virtcol();
9397 return curwin->w_virtcol;
9398}