blob: 53eabe667f22aea599af83ed370aac3ca35c8f3b [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 Moolenaar488c6512005-08-11 20:09:58 +000043 N_(" ^X mode (^]^D^E^F^I^K^L^N^O^P^S^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 Moolenaar488c6512005-08-11 20:09:58 +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 Moolenaar572cb562005-08-05 21:35:02 +000065typedef struct Completion compl_T;
Bram Moolenaar071d4272004-06-13 20:20:40 +000066struct Completion
67{
Bram Moolenaar572cb562005-08-05 21:35:02 +000068 compl_T *cp_next;
69 compl_T *cp_prev;
70 char_u *cp_str; /* matched text */
71 char_u *cp_fname; /* file containing the match */
72 int cp_flags; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
73 int cp_number; /* sequence number */
Bram Moolenaar071d4272004-06-13 20:20:40 +000074};
75
Bram Moolenaar572cb562005-08-05 21:35:02 +000076#define ORIGINAL_TEXT (1) /* the original text when the expansion begun */
Bram Moolenaar071d4272004-06-13 20:20:40 +000077#define FREE_FNAME (2)
78
79/*
80 * All the current matches are stored in a list.
Bram Moolenaar4be06f92005-07-29 22:36:03 +000081 * "compl_first_match" points to the start of the list.
82 * "compl_curr_match" points to the currently selected entry.
83 * "compl_shown_match" is different from compl_curr_match during
84 * ins_compl_get_exp().
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 */
Bram Moolenaar572cb562005-08-05 21:35:02 +000086static compl_T *compl_first_match = NULL;
87static compl_T *compl_curr_match = NULL;
88static compl_T *compl_shown_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +000089
Bram Moolenaar4be06f92005-07-29 22:36:03 +000090/* When the first completion is done "compl_started" is set. When it's
91 * FALSE the word to be completed must be located. */
92static int compl_started = FALSE;
93
Bram Moolenaar572cb562005-08-05 21:35:02 +000094static int compl_matches = 0;
95static char_u *compl_pattern = NULL;
96static int compl_direction = FORWARD;
97static int compl_shows_dir = FORWARD;
98static int compl_pending = FALSE;
99static pos_T compl_startpos;
100static colnr_T compl_col = 0; /* column where the text starts
101 * that is being completed */
102static int save_sm = -1;
103static char_u *compl_orig_text = NULL; /* text as it was before
104 * completion started */
105static int compl_cont_mode = 0;
106static expand_T compl_xp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000108static void ins_ctrl_x __ARGS((void));
109static int has_compl_option __ARGS((int dict_opt));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110static void ins_compl_add_matches __ARGS((int num_matches, char_u **matches, int dir));
111static int ins_compl_make_cyclic __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000112static void ins_compl_upd_pum __ARGS((void));
113static void ins_compl_del_pum __ARGS((void));
114static int pum_wanted __ARGS((void));
115static void ins_compl_show_pum __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int dir, int flags, int thesaurus));
117static void ins_compl_free __ARGS((void));
118static void ins_compl_clear __ARGS((void));
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000119static int ins_compl_prep __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));
121static int ins_compl_get_exp __ARGS((pos_T *ini, int dir));
122static void ins_compl_delete __ARGS((void));
123static void ins_compl_insert __ARGS((void));
Bram Moolenaare3226be2005-12-18 22:10:00 +0000124static int ins_compl_next __ARGS((int allow_get_expansion, int count));
125static int ins_compl_key2dir __ARGS((int c));
126static int ins_compl_key2count __ARGS((int c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127static int ins_complete __ARGS((int c));
128static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
129#endif /* FEAT_INS_EXPAND */
130
131#define BACKSPACE_CHAR 1
132#define BACKSPACE_WORD 2
133#define BACKSPACE_WORD_NOT_SPACE 3
134#define BACKSPACE_LINE 4
135
136static void ins_redraw __ARGS((void));
137static void ins_ctrl_v __ARGS((void));
138static void undisplay_dollar __ARGS((void));
139static void insert_special __ARGS((int, int, int));
140static void check_auto_format __ARGS((int));
141static void redo_literal __ARGS((int c));
142static void start_arrow __ARGS((pos_T *end_insert_pos));
Bram Moolenaar217ad922005-03-20 22:37:15 +0000143#ifdef FEAT_SYN_HL
144static void check_spell_redraw __ARGS((void));
Bram Moolenaar8aff23a2005-08-19 20:40:30 +0000145static void spell_back_to_badword __ARGS((void));
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +0000146static int spell_bad_len = 0; /* length of located bad word */
Bram Moolenaar217ad922005-03-20 22:37:15 +0000147#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148static void stop_insert __ARGS((pos_T *end_insert_pos, int esc));
149static int echeck_abbr __ARGS((int));
150static void replace_push_off __ARGS((int c));
151static int replace_pop __ARGS((void));
152static void replace_join __ARGS((int off));
153static void replace_pop_ins __ARGS((void));
154#ifdef FEAT_MBYTE
155static void mb_replace_pop_ins __ARGS((int cc));
156#endif
157static void replace_flush __ARGS((void));
158static void replace_do_bs __ARGS((void));
159#ifdef FEAT_CINDENT
160static int cindent_on __ARGS((void));
161#endif
162static void ins_reg __ARGS((void));
163static void ins_ctrl_g __ARGS((void));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000164static void ins_ctrl_hat __ARGS((void));
Bram Moolenaar488c6512005-08-11 20:09:58 +0000165static int ins_esc __ARGS((long *count, int cmdchar, int nomove));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166#ifdef FEAT_RIGHTLEFT
167static void ins_ctrl_ __ARGS((void));
168#endif
169#ifdef FEAT_VISUAL
170static int ins_start_select __ARGS((int c));
171#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000172static void ins_insert __ARGS((int replaceState));
173static void ins_ctrl_o __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174static void ins_shift __ARGS((int c, int lastc));
175static void ins_del __ARGS((void));
176static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
177#ifdef FEAT_MOUSE
178static void ins_mouse __ARGS((int c));
179static void ins_mousescroll __ARGS((int up));
180#endif
181static void ins_left __ARGS((void));
182static void ins_home __ARGS((int c));
183static void ins_end __ARGS((int c));
184static void ins_s_left __ARGS((void));
185static void ins_right __ARGS((void));
186static void ins_s_right __ARGS((void));
187static void ins_up __ARGS((int startcol));
188static void ins_pageup __ARGS((void));
189static void ins_down __ARGS((int startcol));
190static void ins_pagedown __ARGS((void));
191#ifdef FEAT_DND
192static void ins_drop __ARGS((void));
193#endif
194static int ins_tab __ARGS((void));
195static int ins_eol __ARGS((int c));
196#ifdef FEAT_DIGRAPHS
197static int ins_digraph __ARGS((void));
198#endif
199static int ins_copychar __ARGS((linenr_T lnum));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000200static int ins_ctrl_ey __ARGS((int tc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#ifdef FEAT_SMARTINDENT
202static void ins_try_si __ARGS((int c));
203#endif
204static colnr_T get_nolist_virtcol __ARGS((void));
205
206static colnr_T Insstart_textlen; /* length of line when insert started */
207static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
208
209static char_u *last_insert = NULL; /* the text of the previous insert,
210 K_SPECIAL and CSI are escaped */
211static int last_insert_skip; /* nr of chars in front of previous insert */
212static int new_insert_skip; /* nr of chars in front of current insert */
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000213static int did_restart_edit; /* "restart_edit" when calling edit() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214
215#ifdef FEAT_CINDENT
216static int can_cindent; /* may do cindenting on this line */
217#endif
218
219static int old_indent = 0; /* for ^^D command in insert mode */
220
221#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +0000222static int revins_on; /* reverse insert mode on */
223static int revins_chars; /* how much to skip after edit */
224static int revins_legal; /* was the last char 'legal'? */
225static int revins_scol; /* start column of revins session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226#endif
227
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228static int ins_need_undo; /* call u_save() before inserting a
229 char. Set when edit() is called.
230 after that arrow_used is used. */
231
232static int did_add_space = FALSE; /* auto_format() added an extra space
233 under the cursor */
234
235/*
236 * edit(): Start inserting text.
237 *
238 * "cmdchar" can be:
239 * 'i' normal insert command
240 * 'a' normal append command
241 * 'R' replace command
242 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
243 * but still only one <CR> is inserted. The <Esc> is not used for redo.
244 * 'g' "gI" command.
245 * 'V' "gR" command for Virtual Replace mode.
246 * 'v' "gr" command for single character Virtual Replace mode.
247 *
248 * This function is not called recursively. For CTRL-O commands, it returns
249 * and lets the caller handle the Normal-mode command.
250 *
251 * Return TRUE if a CTRL-O command caused the return (insert mode pending).
252 */
253 int
254edit(cmdchar, startln, count)
255 int cmdchar;
256 int startln; /* if set, insert at start of line */
257 long count;
258{
259 int c = 0;
260 char_u *ptr;
261 int lastc;
262 colnr_T mincol;
263 static linenr_T o_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 int i;
265 int did_backspace = TRUE; /* previous char was backspace */
266#ifdef FEAT_CINDENT
267 int line_is_white = FALSE; /* line is empty before insert */
268#endif
269 linenr_T old_topline = 0; /* topline before insertion */
270#ifdef FEAT_DIFF
271 int old_topfill = -1;
272#endif
273 int inserted_space = FALSE; /* just inserted a space */
274 int replaceState = REPLACE;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000275 int nomove = FALSE; /* don't move cursor on return */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000277 /* Remember whether editing was restarted after CTRL-O. */
278 did_restart_edit = restart_edit;
279
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 /* sleep before redrawing, needed for "CTRL-O :" that results in an
281 * error message */
282 check_for_delay(TRUE);
283
284#ifdef HAVE_SANDBOX
285 /* Don't allow inserting in the sandbox. */
286 if (sandbox != 0)
287 {
288 EMSG(_(e_sandbox));
289 return FALSE;
290 }
291#endif
292
293#ifdef FEAT_INS_EXPAND
294 ins_compl_clear(); /* clear stuff for CTRL-X mode */
295#endif
296
Bram Moolenaar843ee412004-06-30 16:16:41 +0000297#ifdef FEAT_AUTOCMD
298 /*
299 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
300 */
301 if (cmdchar != 'r' && cmdchar != 'v')
302 {
Bram Moolenaar1e015462005-09-25 22:16:38 +0000303# ifdef FEAT_EVAL
Bram Moolenaar843ee412004-06-30 16:16:41 +0000304 if (cmdchar == 'R')
305 ptr = (char_u *)"r";
306 else if (cmdchar == 'V')
307 ptr = (char_u *)"v";
308 else
309 ptr = (char_u *)"i";
310 set_vim_var_string(VV_INSERTMODE, ptr, 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +0000311# endif
Bram Moolenaar843ee412004-06-30 16:16:41 +0000312 apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);
313 }
314#endif
315
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316#ifdef FEAT_MOUSE
317 /*
318 * When doing a paste with the middle mouse button, Insstart is set to
319 * where the paste started.
320 */
321 if (where_paste_started.lnum != 0)
322 Insstart = where_paste_started;
323 else
324#endif
325 {
326 Insstart = curwin->w_cursor;
327 if (startln)
328 Insstart.col = 0;
329 }
330 Insstart_textlen = linetabsize(ml_get_curline());
331 Insstart_blank_vcol = MAXCOL;
332 if (!did_ai)
333 ai_col = 0;
334
335 if (cmdchar != NUL && restart_edit == 0)
336 {
337 ResetRedobuff();
338 AppendNumberToRedobuff(count);
339#ifdef FEAT_VREPLACE
340 if (cmdchar == 'V' || cmdchar == 'v')
341 {
342 /* "gR" or "gr" command */
343 AppendCharToRedobuff('g');
344 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
345 }
346 else
347#endif
348 {
349 AppendCharToRedobuff(cmdchar);
350 if (cmdchar == 'g') /* "gI" command */
351 AppendCharToRedobuff('I');
352 else if (cmdchar == 'r') /* "r<CR>" command */
353 count = 1; /* insert only one <CR> */
354 }
355 }
356
357 if (cmdchar == 'R')
358 {
359#ifdef FEAT_FKMAP
360 if (p_fkmap && p_ri)
361 {
362 beep_flush();
363 EMSG(farsi_text_3); /* encoded in Farsi */
364 State = INSERT;
365 }
366 else
367#endif
368 State = REPLACE;
369 }
370#ifdef FEAT_VREPLACE
371 else if (cmdchar == 'V' || cmdchar == 'v')
372 {
373 State = VREPLACE;
374 replaceState = VREPLACE;
375 orig_line_count = curbuf->b_ml.ml_line_count;
376 vr_lines_changed = 1;
377 }
378#endif
379 else
380 State = INSERT;
381
382 stop_insert_mode = FALSE;
383
384 /*
385 * Need to recompute the cursor position, it might move when the cursor is
386 * on a TAB or special character.
387 */
388 curs_columns(TRUE);
389
390 /*
391 * Enable langmap or IME, indicated by 'iminsert'.
392 * Note that IME may enabled/disabled without us noticing here, thus the
393 * 'iminsert' value may not reflect what is actually used. It is updated
394 * when hitting <Esc>.
395 */
396 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
397 State |= LANGMAP;
398#ifdef USE_IM_CONTROL
399 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
400#endif
401
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402#ifdef FEAT_MOUSE
403 setmouse();
404#endif
405#ifdef FEAT_CMDL_INFO
406 clear_showcmd();
407#endif
408#ifdef FEAT_RIGHTLEFT
409 /* there is no reverse replace mode */
410 revins_on = (State == INSERT && p_ri);
411 if (revins_on)
412 undisplay_dollar();
413 revins_chars = 0;
414 revins_legal = 0;
415 revins_scol = -1;
416#endif
417
418 /*
419 * Handle restarting Insert mode.
420 * Don't do this for "CTRL-O ." (repeat an insert): we get here with
421 * restart_edit non-zero, and something in the stuff buffer.
422 */
423 if (restart_edit != 0 && stuff_empty())
424 {
425#ifdef FEAT_MOUSE
426 /*
427 * After a paste we consider text typed to be part of the insert for
428 * the pasted text. You can backspace over the pasted text too.
429 */
430 if (where_paste_started.lnum)
431 arrow_used = FALSE;
432 else
433#endif
434 arrow_used = TRUE;
435 restart_edit = 0;
436
437 /*
438 * If the cursor was after the end-of-line before the CTRL-O and it is
439 * now at the end-of-line, put it after the end-of-line (this is not
440 * correct in very rare cases).
441 * Also do this if curswant is greater than the current virtual
442 * column. Eg after "^O$" or "^O80|".
443 */
444 validate_virtcol();
445 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000446 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447 || curwin->w_curswant > curwin->w_virtcol)
448 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
449 {
450 if (ptr[1] == NUL)
451 ++curwin->w_cursor.col;
452#ifdef FEAT_MBYTE
453 else if (has_mbyte)
454 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000455 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 if (ptr[i] == NUL)
457 curwin->w_cursor.col += i;
458 }
459#endif
460 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000461 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 }
463 else
464 arrow_used = FALSE;
465
466 /* we are in insert mode now, don't need to start it anymore */
467 need_start_insertmode = FALSE;
468
469 /* Need to save the line for undo before inserting the first char. */
470 ins_need_undo = TRUE;
471
472#ifdef FEAT_MOUSE
473 where_paste_started.lnum = 0;
474#endif
475#ifdef FEAT_CINDENT
476 can_cindent = TRUE;
477#endif
478#ifdef FEAT_FOLDING
479 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
480 * restarting. */
481 if (!p_im && did_restart_edit == 0)
482 foldOpenCursor();
483#endif
484
485 /*
486 * If 'showmode' is set, show the current (insert/replace/..) mode.
487 * A warning message for changing a readonly file is given here, before
488 * actually changing anything. It's put after the mode, if any.
489 */
490 i = 0;
491 if (p_smd)
492 i = showmode();
493
494 if (!p_im && did_restart_edit == 0)
495 change_warning(i + 1);
496
497#ifdef CURSOR_SHAPE
498 ui_cursor_shape(); /* may show different cursor shape */
499#endif
500#ifdef FEAT_DIGRAPHS
501 do_digraph(-1); /* clear digraphs */
502#endif
503
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000504 /*
505 * Get the current length of the redo buffer, those characters have to be
506 * skipped if we want to get to the inserted characters.
507 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 ptr = get_inserted();
509 if (ptr == NULL)
510 new_insert_skip = 0;
511 else
512 {
513 new_insert_skip = (int)STRLEN(ptr);
514 vim_free(ptr);
515 }
516
517 old_indent = 0;
518
519 /*
520 * Main loop in Insert mode: repeat until Insert mode is left.
521 */
522 for (;;)
523 {
524#ifdef FEAT_RIGHTLEFT
525 if (!revins_legal)
526 revins_scol = -1; /* reset on illegal motions */
527 else
528 revins_legal = 0;
529#endif
530 if (arrow_used) /* don't repeat insert when arrow key used */
531 count = 0;
532
533 if (stop_insert_mode)
534 {
535 /* ":stopinsert" used or 'insertmode' reset */
536 count = 0;
537 goto doESCkey;
538 }
539
540 /* set curwin->w_curswant for next K_DOWN or K_UP */
541 if (!arrow_used)
542 curwin->w_set_curswant = TRUE;
543
544 /* If there is no typeahead may check for timestamps (e.g., for when a
545 * menu invoked a shell command). */
546 if (stuff_empty())
547 {
548 did_check_timestamps = FALSE;
549 if (need_check_timestamps)
550 check_timestamps(FALSE);
551 }
552
553 /*
554 * When emsg() was called msg_scroll will have been set.
555 */
556 msg_scroll = FALSE;
557
558#ifdef FEAT_GUI
559 /* When 'mousefocus' is set a mouse movement may have taken us to
560 * another window. "need_mouse_correct" may then be set because of an
561 * autocommand. */
562 if (need_mouse_correct)
563 gui_mouse_correct();
564#endif
565
566#ifdef FEAT_FOLDING
567 /* Open fold at the cursor line, according to 'foldopen'. */
568 if (fdo_flags & FDO_INSERT)
569 foldOpenCursor();
570 /* Close folds where the cursor isn't, according to 'foldclose' */
571 if (!char_avail())
572 foldCheckClose();
573#endif
574
575 /*
576 * If we inserted a character at the last position of the last line in
577 * the window, scroll the window one line up. This avoids an extra
578 * redraw.
579 * This is detected when the cursor column is smaller after inserting
580 * something.
581 * Don't do this when the topline changed already, it has
582 * already been adjusted (by insertchar() calling open_line())).
583 */
584 if (curbuf->b_mod_set
585 && curwin->w_p_wrap
586 && !did_backspace
587 && curwin->w_topline == old_topline
588#ifdef FEAT_DIFF
589 && curwin->w_topfill == old_topfill
590#endif
591 )
592 {
593 mincol = curwin->w_wcol;
594 validate_cursor_col();
595
596 if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts
597 && curwin->w_wrow == W_WINROW(curwin)
598 + curwin->w_height - 1 - p_so
599 && (curwin->w_cursor.lnum != curwin->w_topline
600#ifdef FEAT_DIFF
601 || curwin->w_topfill > 0
602#endif
603 ))
604 {
605#ifdef FEAT_DIFF
606 if (curwin->w_topfill > 0)
607 --curwin->w_topfill;
608 else
609#endif
610#ifdef FEAT_FOLDING
611 if (hasFolding(curwin->w_topline, NULL, &old_topline))
612 set_topline(curwin, old_topline + 1);
613 else
614#endif
615 set_topline(curwin, curwin->w_topline + 1);
616 }
617 }
618
619 /* May need to adjust w_topline to show the cursor. */
620 update_topline();
621
622 did_backspace = FALSE;
623
624 validate_cursor(); /* may set must_redraw */
625
626 /*
627 * Redraw the display when no characters are waiting.
628 * Also shows mode, ruler and positions cursor.
629 */
630 ins_redraw();
631
632#ifdef FEAT_SCROLLBIND
633 if (curwin->w_p_scb)
634 do_check_scrollbind(TRUE);
635#endif
636
637 update_curswant();
638 old_topline = curwin->w_topline;
639#ifdef FEAT_DIFF
640 old_topfill = curwin->w_topfill;
641#endif
642
643#ifdef USE_ON_FLY_SCROLL
644 dont_scroll = FALSE; /* allow scrolling here */
645#endif
646
647 /*
648 * Get a character for Insert mode.
649 */
650 lastc = c; /* remember previous char for CTRL-D */
651 c = safe_vgetc();
652
653#ifdef FEAT_RIGHTLEFT
654 if (p_hkmap && KeyTyped)
655 c = hkmap(c); /* Hebrew mode mapping */
656#endif
657#ifdef FEAT_FKMAP
658 if (p_fkmap && KeyTyped)
659 c = fkmap(c); /* Farsi mode mapping */
660#endif
661
662#ifdef FEAT_INS_EXPAND
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000663 /* When the popup menu is visible cursor keys change the selection. */
664 if (c == K_UP && pum_visible())
665 c = Ctrl_P;
666 if (c == K_DOWN && pum_visible())
667 c = Ctrl_N;
668
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
670 * it does fix up the text when finishing completion. */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000671 if (c != K_IGNORE)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +0000672 {
673 if (ins_compl_prep(c))
674 continue;
675 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676#endif
677
Bram Moolenaar488c6512005-08-11 20:09:58 +0000678 /* CTRL-\ CTRL-N goes to Normal mode,
679 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
680 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 if (c == Ctrl_BSL)
682 {
683 /* may need to redraw when no more chars available now */
684 ins_redraw();
685 ++no_mapping;
686 ++allow_keys;
687 c = safe_vgetc();
688 --no_mapping;
689 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000690 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000692 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693 vungetc(c);
694 c = Ctrl_BSL;
695 }
696 else if (c == Ctrl_G && p_im)
697 continue;
698 else
699 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000700 if (c == Ctrl_O)
701 {
702 ins_ctrl_o();
703 ins_at_eol = FALSE; /* cursor keeps its column */
704 nomove = TRUE;
705 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 count = 0;
707 goto doESCkey;
708 }
709 }
710
711#ifdef FEAT_DIGRAPHS
712 c = do_digraph(c);
713#endif
714
715#ifdef FEAT_INS_EXPAND
716 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
717 goto docomplete;
718#endif
719 if (c == Ctrl_V || c == Ctrl_Q)
720 {
721 ins_ctrl_v();
722 c = Ctrl_V; /* pretend CTRL-V is last typed character */
723 continue;
724 }
725
726#ifdef FEAT_CINDENT
727 if (cindent_on()
728# ifdef FEAT_INS_EXPAND
729 && ctrl_x_mode == 0
730# endif
731 )
732 {
733 /* A key name preceded by a bang means this key is not to be
734 * inserted. Skip ahead to the re-indenting below.
735 * A key name preceded by a star means that indenting has to be
736 * done before inserting the key. */
737 line_is_white = inindent(0);
738 if (in_cinkeys(c, '!', line_is_white))
739 goto force_cindent;
740 if (can_cindent && in_cinkeys(c, '*', line_is_white)
741 && stop_arrow() == OK)
742 do_c_expr_indent();
743 }
744#endif
745
746#ifdef FEAT_RIGHTLEFT
747 if (curwin->w_p_rl)
748 switch (c)
749 {
750 case K_LEFT: c = K_RIGHT; break;
751 case K_S_LEFT: c = K_S_RIGHT; break;
752 case K_C_LEFT: c = K_C_RIGHT; break;
753 case K_RIGHT: c = K_LEFT; break;
754 case K_S_RIGHT: c = K_S_LEFT; break;
755 case K_C_RIGHT: c = K_C_LEFT; break;
756 }
757#endif
758
759#ifdef FEAT_VISUAL
760 /*
761 * If 'keymodel' contains "startsel", may start selection. If it
762 * does, a CTRL-O and c will be stuffed, we need to get these
763 * characters.
764 */
765 if (ins_start_select(c))
766 continue;
767#endif
768
769 /*
770 * The big switch to handle a character in insert mode.
771 */
772 switch (c)
773 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000774 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 if (echeck_abbr(ESC + ABBR_OFF))
776 break;
777 /*FALLTHROUGH*/
778
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000779 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780#ifdef FEAT_CMDWIN
781 if (c == Ctrl_C && cmdwin_type != 0)
782 {
783 /* Close the cmdline window. */
784 cmdwin_result = K_IGNORE;
785 got_int = FALSE; /* don't stop executing autocommands et al. */
786 goto doESCkey;
787 }
788#endif
789
790#ifdef UNIX
791do_intr:
792#endif
793 /* when 'insertmode' set, and not halfway a mapping, don't leave
794 * Insert mode */
795 if (goto_im())
796 {
797 if (got_int)
798 {
799 (void)vgetc(); /* flush all buffers */
800 got_int = FALSE;
801 }
802 else
803 vim_beep();
804 break;
805 }
806doESCkey:
807 /*
808 * This is the ONLY return from edit()!
809 */
810 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
811 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000812 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 o_lnum = curwin->w_cursor.lnum;
814
Bram Moolenaar488c6512005-08-11 20:09:58 +0000815 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000816 {
817#ifdef FEAT_AUTOCMD
818 if (cmdchar != 'r' && cmdchar != 'v')
819 apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL,
820 FALSE, curbuf);
821#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000823 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 continue;
825
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000826 case Ctrl_Z: /* suspend when 'insertmode' set */
827 if (!p_im)
828 goto normalchar; /* insert CTRL-Z as normal char */
829 stuffReadbuff((char_u *)":st\r");
830 c = Ctrl_O;
831 /*FALLTHROUGH*/
832
833 case Ctrl_O: /* execute one command */
Bram Moolenaare344bea2005-09-01 20:46:49 +0000834#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000835 if (ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000836 goto docomplete;
837#endif
838 if (echeck_abbr(Ctrl_O + ABBR_OFF))
839 break;
840 ins_ctrl_o();
841 count = 0;
842 goto doESCkey;
843
Bram Moolenaar572cb562005-08-05 21:35:02 +0000844 case K_INS: /* toggle insert/replace mode */
845 case K_KINS:
846 ins_insert(replaceState);
847 break;
848
849 case K_SELECT: /* end of Select mode mapping - ignore */
850 break;
851
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000852#ifdef FEAT_SNIFF
853 case K_SNIFF: /* Sniff command received */
854 stuffcharReadbuff(K_SNIFF);
855 goto doESCkey;
856#endif
857
858 case K_HELP: /* Help key works like <ESC> <Help> */
859 case K_F1:
860 case K_XF1:
861 stuffcharReadbuff(K_HELP);
862 if (p_im)
863 need_start_insertmode = TRUE;
864 goto doESCkey;
865
866#ifdef FEAT_NETBEANS_INTG
867 case K_F21: /* NetBeans command */
868 ++no_mapping; /* don't map the next key hits */
869 i = safe_vgetc();
870 --no_mapping;
871 netbeans_keycommand(i);
872 break;
873#endif
874
875 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 case NUL:
877 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000878 /* For ^@ the trailing ESC will end the insert, unless there is an
879 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
881 && c != Ctrl_A && !p_im)
882 goto doESCkey; /* quit insert mode */
883 inserted_space = FALSE;
884 break;
885
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000886 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 ins_reg();
888 auto_format(FALSE, TRUE);
889 inserted_space = FALSE;
890 break;
891
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000892 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 ins_ctrl_g();
894 break;
895
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000896 case Ctrl_HAT: /* switch input mode and/or langmap */
897 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 break;
899
900#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000901 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 if (!p_ari)
903 goto normalchar;
904 ins_ctrl_();
905 break;
906#endif
907
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000908 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
910 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
911 goto docomplete;
912#endif
913 /* FALLTHROUGH */
914
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000915 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916# ifdef FEAT_INS_EXPAND
917 if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
918 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000919 if (has_compl_option(FALSE))
920 goto docomplete;
921 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 }
923# endif
924 ins_shift(c, lastc);
925 auto_format(FALSE, TRUE);
926 inserted_space = FALSE;
927 break;
928
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000929 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 case K_KDEL:
931 ins_del();
932 auto_format(FALSE, TRUE);
933 break;
934
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000935 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 case Ctrl_H:
937 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
938 auto_format(FALSE, TRUE);
939 break;
940
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000941 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
943 auto_format(FALSE, TRUE);
944 break;
945
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000946 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000947# ifdef FEAT_COMPL_FUNC
948 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000949 if (ctrl_x_mode == CTRL_X_FUNCTION)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000950 goto docomplete;
951# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
953 auto_format(FALSE, TRUE);
954 inserted_space = FALSE;
955 break;
956
957#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000958 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 case K_LEFTMOUSE_NM:
960 case K_LEFTDRAG:
961 case K_LEFTRELEASE:
962 case K_LEFTRELEASE_NM:
963 case K_MIDDLEMOUSE:
964 case K_MIDDLEDRAG:
965 case K_MIDDLERELEASE:
966 case K_RIGHTMOUSE:
967 case K_RIGHTDRAG:
968 case K_RIGHTRELEASE:
969 case K_X1MOUSE:
970 case K_X1DRAG:
971 case K_X1RELEASE:
972 case K_X2MOUSE:
973 case K_X2DRAG:
974 case K_X2RELEASE:
975 ins_mouse(c);
976 break;
977
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000978 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 ins_mousescroll(FALSE);
980 break;
981
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000982 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983 ins_mousescroll(TRUE);
984 break;
985#endif
986
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000987 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 break;
989
990#ifdef FEAT_GUI
991 case K_VER_SCROLLBAR:
992 ins_scroll();
993 break;
994
995 case K_HOR_SCROLLBAR:
996 ins_horscroll();
997 break;
998#endif
999
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001000 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001002 case K_S_HOME:
1003 case K_C_HOME:
1004 ins_home(c);
1005 break;
1006
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001007 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 case K_S_END:
1010 case K_C_END:
1011 ins_end(c);
1012 break;
1013
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001014 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001015 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1016 ins_s_left();
1017 else
1018 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019 break;
1020
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001021 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022 case K_C_LEFT:
1023 ins_s_left();
1024 break;
1025
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001026 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001027 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1028 ins_s_right();
1029 else
1030 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 break;
1032
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001033 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001034 case K_C_RIGHT:
1035 ins_s_right();
1036 break;
1037
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001038 case K_UP: /* <Up> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001039 if (mod_mask & MOD_MASK_SHIFT)
1040 ins_pageup();
1041 else
1042 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 break;
1044
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001045 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 case K_PAGEUP:
1047 case K_KPAGEUP:
Bram Moolenaare3226be2005-12-18 22:10:00 +00001048 if (pum_visible())
1049 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050 ins_pageup();
1051 break;
1052
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001053 case K_DOWN: /* <Down> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001054 if (mod_mask & MOD_MASK_SHIFT)
1055 ins_pagedown();
1056 else
1057 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 break;
1059
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001060 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001061 case K_PAGEDOWN:
1062 case K_KPAGEDOWN:
Bram Moolenaare3226be2005-12-18 22:10:00 +00001063 if (pum_visible())
1064 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065 ins_pagedown();
1066 break;
1067
1068#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001069 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 ins_drop();
1071 break;
1072#endif
1073
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001074 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 c = TAB;
1076 /* FALLTHROUGH */
1077
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001078 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1080 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
1081 goto docomplete;
1082#endif
1083 inserted_space = FALSE;
1084 if (ins_tab())
1085 goto normalchar; /* insert TAB as a normal char */
1086 auto_format(FALSE, TRUE);
1087 break;
1088
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001089 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 c = CAR;
1091 /* FALLTHROUGH */
1092 case CAR:
1093 case NL:
1094#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
1095 /* In a quickfix window a <CR> jumps to the error under the
1096 * cursor. */
1097 if (bt_quickfix(curbuf) && c == CAR)
1098 {
1099 do_cmdline_cmd((char_u *)".cc");
1100 break;
1101 }
1102#endif
1103#ifdef FEAT_CMDWIN
1104 if (cmdwin_type != 0)
1105 {
1106 /* Execute the command in the cmdline window. */
1107 cmdwin_result = CAR;
1108 goto doESCkey;
1109 }
1110#endif
1111 if (ins_eol(c) && !p_im)
1112 goto doESCkey; /* out of memory */
1113 auto_format(FALSE, FALSE);
1114 inserted_space = FALSE;
1115 break;
1116
1117#if defined(FEAT_DIGRAPHS) || defined (FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001118 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119# ifdef FEAT_INS_EXPAND
1120 if (ctrl_x_mode == CTRL_X_DICTIONARY)
1121 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001122 if (has_compl_option(TRUE))
1123 goto docomplete;
1124 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 }
1126# endif
1127# ifdef FEAT_DIGRAPHS
1128 c = ins_digraph();
1129 if (c == NUL)
1130 break;
1131# endif
1132 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001133#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134
1135#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001136 case Ctrl_X: /* Enter CTRL-X mode */
1137 ins_ctrl_x();
1138 break;
1139
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001140 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 if (ctrl_x_mode != CTRL_X_TAGS)
1142 goto normalchar;
1143 goto docomplete;
1144
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001145 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 if (ctrl_x_mode != CTRL_X_FILES)
1147 goto normalchar;
1148 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001149
1150 case 's': /* Spelling completion after ^X */
1151 case Ctrl_S:
1152 if (ctrl_x_mode != CTRL_X_SPELL)
1153 goto normalchar;
1154 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155#endif
1156
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001157 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158#ifdef FEAT_INS_EXPAND
1159 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
1160#endif
1161 {
1162 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1163 if (p_im)
1164 {
1165 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1166 break;
1167 goto doESCkey;
1168 }
1169 goto normalchar;
1170 }
1171#ifdef FEAT_INS_EXPAND
1172 /* FALLTHROUGH */
1173
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001174 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 case Ctrl_N:
1176 /* if 'complete' is empty then plain ^P is no longer special,
1177 * but it is under other ^X modes */
1178 if (*curbuf->b_p_cpt == NUL
1179 && ctrl_x_mode != 0
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001180 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 goto normalchar;
1182
1183docomplete:
1184 if (ins_complete(c) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001185 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 break;
1187#endif /* FEAT_INS_EXPAND */
1188
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001189 case Ctrl_Y: /* copy from previous line or scroll down */
1190 case Ctrl_E: /* copy from next line or scroll up */
1191 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 break;
1193
1194 default:
1195#ifdef UNIX
1196 if (c == intr_char) /* special interrupt char */
1197 goto do_intr;
1198#endif
1199
1200 /*
1201 * Insert a nomal character.
1202 */
1203normalchar:
1204#ifdef FEAT_SMARTINDENT
1205 /* Try to perform smart-indenting. */
1206 ins_try_si(c);
1207#endif
1208
1209 if (c == ' ')
1210 {
1211 inserted_space = TRUE;
1212#ifdef FEAT_CINDENT
1213 if (inindent(0))
1214 can_cindent = FALSE;
1215#endif
1216 if (Insstart_blank_vcol == MAXCOL
1217 && curwin->w_cursor.lnum == Insstart.lnum)
1218 Insstart_blank_vcol = get_nolist_virtcol();
1219 }
1220
1221 if (vim_iswordc(c) || !echeck_abbr(
1222#ifdef FEAT_MBYTE
1223 /* Add ABBR_OFF for characters above 0x100, this is
1224 * what check_abbr() expects. */
1225 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1226#endif
1227 c))
1228 {
1229 insert_special(c, FALSE, FALSE);
1230#ifdef FEAT_RIGHTLEFT
1231 revins_legal++;
1232 revins_chars++;
1233#endif
1234 }
1235
1236 auto_format(FALSE, TRUE);
1237
1238#ifdef FEAT_FOLDING
1239 /* When inserting a character the cursor line must never be in a
1240 * closed fold. */
1241 foldOpenCursor();
1242#endif
1243 break;
1244 } /* end of switch (c) */
1245
1246 /* If the cursor was moved we didn't just insert a space */
1247 if (arrow_used)
1248 inserted_space = FALSE;
1249
1250#ifdef FEAT_CINDENT
1251 if (can_cindent && cindent_on()
1252# ifdef FEAT_INS_EXPAND
1253 && ctrl_x_mode == 0
1254# endif
1255 )
1256 {
1257force_cindent:
1258 /*
1259 * Indent now if a key was typed that is in 'cinkeys'.
1260 */
1261 if (in_cinkeys(c, ' ', line_is_white))
1262 {
1263 if (stop_arrow() == OK)
1264 /* re-indent the current line */
1265 do_c_expr_indent();
1266 }
1267 }
1268#endif /* FEAT_CINDENT */
1269
1270 } /* for (;;) */
1271 /* NOTREACHED */
1272}
1273
1274/*
1275 * Redraw for Insert mode.
1276 * This is postponed until getting the next character to make '$' in the 'cpo'
1277 * option work correctly.
1278 * Only redraw when there are no characters available. This speeds up
1279 * inserting sequences of characters (e.g., for CTRL-R).
1280 */
1281 static void
1282ins_redraw()
1283{
1284 if (!char_avail())
1285 {
1286 if (must_redraw)
1287 update_screen(0);
1288 else if (clear_cmdline || redraw_cmdline)
1289 showmode(); /* clear cmdline and show mode */
1290 showruler(FALSE);
1291 setcursor();
1292 emsg_on_display = FALSE; /* may remove error message now */
1293 }
1294}
1295
1296/*
1297 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1298 */
1299 static void
1300ins_ctrl_v()
1301{
1302 int c;
1303
1304 /* may need to redraw when no more chars available now */
1305 ins_redraw();
1306
1307 if (redrawing() && !char_avail())
1308 edit_putchar('^', TRUE);
1309 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1310
1311#ifdef FEAT_CMDL_INFO
1312 add_to_showcmd_c(Ctrl_V);
1313#endif
1314
1315 c = get_literal();
1316#ifdef FEAT_CMDL_INFO
1317 clear_showcmd();
1318#endif
1319 insert_special(c, FALSE, TRUE);
1320#ifdef FEAT_RIGHTLEFT
1321 revins_chars++;
1322 revins_legal++;
1323#endif
1324}
1325
1326/*
1327 * Put a character directly onto the screen. It's not stored in a buffer.
1328 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1329 */
1330static int pc_status;
1331#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1332#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1333#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1334#define PC_STATUS_SET 3 /* pc_bytes was filled */
1335#ifdef FEAT_MBYTE
1336static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1337#else
1338static char_u pc_bytes[2]; /* saved bytes */
1339#endif
1340static int pc_attr;
1341static int pc_row;
1342static int pc_col;
1343
1344 void
1345edit_putchar(c, highlight)
1346 int c;
1347 int highlight;
1348{
1349 int attr;
1350
1351 if (ScreenLines != NULL)
1352 {
1353 update_topline(); /* just in case w_topline isn't valid */
1354 validate_cursor();
1355 if (highlight)
1356 attr = hl_attr(HLF_8);
1357 else
1358 attr = 0;
1359 pc_row = W_WINROW(curwin) + curwin->w_wrow;
1360 pc_col = W_WINCOL(curwin);
1361#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1362 pc_status = PC_STATUS_UNSET;
1363#endif
1364#ifdef FEAT_RIGHTLEFT
1365 if (curwin->w_p_rl)
1366 {
1367 pc_col += W_WIDTH(curwin) - 1 - curwin->w_wcol;
1368# ifdef FEAT_MBYTE
1369 if (has_mbyte)
1370 {
1371 int fix_col = mb_fix_col(pc_col, pc_row);
1372
1373 if (fix_col != pc_col)
1374 {
1375 screen_putchar(' ', pc_row, fix_col, attr);
1376 --curwin->w_wcol;
1377 pc_status = PC_STATUS_RIGHT;
1378 }
1379 }
1380# endif
1381 }
1382 else
1383#endif
1384 {
1385 pc_col += curwin->w_wcol;
1386#ifdef FEAT_MBYTE
1387 if (mb_lefthalve(pc_row, pc_col))
1388 pc_status = PC_STATUS_LEFT;
1389#endif
1390 }
1391
1392 /* save the character to be able to put it back */
1393#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1394 if (pc_status == PC_STATUS_UNSET)
1395#endif
1396 {
1397 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1398 pc_status = PC_STATUS_SET;
1399 }
1400 screen_putchar(c, pc_row, pc_col, attr);
1401 }
1402}
1403
1404/*
1405 * Undo the previous edit_putchar().
1406 */
1407 void
1408edit_unputchar()
1409{
1410 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1411 {
1412#if defined(FEAT_MBYTE)
1413 if (pc_status == PC_STATUS_RIGHT)
1414 ++curwin->w_wcol;
1415 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
1416 redrawWinline(curwin->w_cursor.lnum, FALSE);
1417 else
1418#endif
1419 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1420 }
1421}
1422
1423/*
1424 * Called when p_dollar is set: display a '$' at the end of the changed text
1425 * Only works when cursor is in the line that changes.
1426 */
1427 void
1428display_dollar(col)
1429 colnr_T col;
1430{
1431 colnr_T save_col;
1432
1433 if (!redrawing())
1434 return;
1435
1436 cursor_off();
1437 save_col = curwin->w_cursor.col;
1438 curwin->w_cursor.col = col;
1439#ifdef FEAT_MBYTE
1440 if (has_mbyte)
1441 {
1442 char_u *p;
1443
1444 /* If on the last byte of a multi-byte move to the first byte. */
1445 p = ml_get_curline();
1446 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1447 }
1448#endif
1449 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
1450 if (curwin->w_wcol < W_WIDTH(curwin))
1451 {
1452 edit_putchar('$', FALSE);
1453 dollar_vcol = curwin->w_virtcol;
1454 }
1455 curwin->w_cursor.col = save_col;
1456}
1457
1458/*
1459 * Call this function before moving the cursor from the normal insert position
1460 * in insert mode.
1461 */
1462 static void
1463undisplay_dollar()
1464{
1465 if (dollar_vcol)
1466 {
1467 dollar_vcol = 0;
1468 redrawWinline(curwin->w_cursor.lnum, FALSE);
1469 }
1470}
1471
1472/*
1473 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1474 * Keep the cursor on the same character.
1475 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1476 * type == INDENT_DEC decrease indent (for CTRL-D)
1477 * type == INDENT_SET set indent to "amount"
1478 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1479 */
1480 void
1481change_indent(type, amount, round, replaced)
1482 int type;
1483 int amount;
1484 int round;
1485 int replaced; /* replaced character, put on replace stack */
1486{
1487 int vcol;
1488 int last_vcol;
1489 int insstart_less; /* reduction for Insstart.col */
1490 int new_cursor_col;
1491 int i;
1492 char_u *ptr;
1493 int save_p_list;
1494 int start_col;
1495 colnr_T vc;
1496#ifdef FEAT_VREPLACE
1497 colnr_T orig_col = 0; /* init for GCC */
1498 char_u *new_line, *orig_line = NULL; /* init for GCC */
1499
1500 /* VREPLACE mode needs to know what the line was like before changing */
1501 if (State & VREPLACE_FLAG)
1502 {
1503 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1504 orig_col = curwin->w_cursor.col;
1505 }
1506#endif
1507
1508 /* for the following tricks we don't want list mode */
1509 save_p_list = curwin->w_p_list;
1510 curwin->w_p_list = FALSE;
1511 vc = getvcol_nolist(&curwin->w_cursor);
1512 vcol = vc;
1513
1514 /*
1515 * For Replace mode we need to fix the replace stack later, which is only
1516 * possible when the cursor is in the indent. Remember the number of
1517 * characters before the cursor if it's possible.
1518 */
1519 start_col = curwin->w_cursor.col;
1520
1521 /* determine offset from first non-blank */
1522 new_cursor_col = curwin->w_cursor.col;
1523 beginline(BL_WHITE);
1524 new_cursor_col -= curwin->w_cursor.col;
1525
1526 insstart_less = curwin->w_cursor.col;
1527
1528 /*
1529 * If the cursor is in the indent, compute how many screen columns the
1530 * cursor is to the left of the first non-blank.
1531 */
1532 if (new_cursor_col < 0)
1533 vcol = get_indent() - vcol;
1534
1535 if (new_cursor_col > 0) /* can't fix replace stack */
1536 start_col = -1;
1537
1538 /*
1539 * Set the new indent. The cursor will be put on the first non-blank.
1540 */
1541 if (type == INDENT_SET)
1542 (void)set_indent(amount, SIN_CHANGED);
1543 else
1544 {
1545#ifdef FEAT_VREPLACE
1546 int save_State = State;
1547
1548 /* Avoid being called recursively. */
1549 if (State & VREPLACE_FLAG)
1550 State = INSERT;
1551#endif
1552 shift_line(type == INDENT_DEC, round, 1);
1553#ifdef FEAT_VREPLACE
1554 State = save_State;
1555#endif
1556 }
1557 insstart_less -= curwin->w_cursor.col;
1558
1559 /*
1560 * Try to put cursor on same character.
1561 * If the cursor is at or after the first non-blank in the line,
1562 * compute the cursor column relative to the column of the first
1563 * non-blank character.
1564 * If we are not in insert mode, leave the cursor on the first non-blank.
1565 * If the cursor is before the first non-blank, position it relative
1566 * to the first non-blank, counted in screen columns.
1567 */
1568 if (new_cursor_col >= 0)
1569 {
1570 /*
1571 * When changing the indent while the cursor is touching it, reset
1572 * Insstart_col to 0.
1573 */
1574 if (new_cursor_col == 0)
1575 insstart_less = MAXCOL;
1576 new_cursor_col += curwin->w_cursor.col;
1577 }
1578 else if (!(State & INSERT))
1579 new_cursor_col = curwin->w_cursor.col;
1580 else
1581 {
1582 /*
1583 * Compute the screen column where the cursor should be.
1584 */
1585 vcol = get_indent() - vcol;
1586 curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
1587
1588 /*
1589 * Advance the cursor until we reach the right screen column.
1590 */
1591 vcol = last_vcol = 0;
1592 new_cursor_col = -1;
1593 ptr = ml_get_curline();
1594 while (vcol <= (int)curwin->w_virtcol)
1595 {
1596 last_vcol = vcol;
1597#ifdef FEAT_MBYTE
1598 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001599 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 else
1601#endif
1602 ++new_cursor_col;
1603 vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
1604 }
1605 vcol = last_vcol;
1606
1607 /*
1608 * May need to insert spaces to be able to position the cursor on
1609 * the right screen column.
1610 */
1611 if (vcol != (int)curwin->w_virtcol)
1612 {
1613 curwin->w_cursor.col = new_cursor_col;
1614 i = (int)curwin->w_virtcol - vcol;
1615 ptr = alloc(i + 1);
1616 if (ptr != NULL)
1617 {
1618 new_cursor_col += i;
1619 ptr[i] = NUL;
1620 while (--i >= 0)
1621 ptr[i] = ' ';
1622 ins_str(ptr);
1623 vim_free(ptr);
1624 }
1625 }
1626
1627 /*
1628 * When changing the indent while the cursor is in it, reset
1629 * Insstart_col to 0.
1630 */
1631 insstart_less = MAXCOL;
1632 }
1633
1634 curwin->w_p_list = save_p_list;
1635
1636 if (new_cursor_col <= 0)
1637 curwin->w_cursor.col = 0;
1638 else
1639 curwin->w_cursor.col = new_cursor_col;
1640 curwin->w_set_curswant = TRUE;
1641 changed_cline_bef_curs();
1642
1643 /*
1644 * May have to adjust the start of the insert.
1645 */
1646 if (State & INSERT)
1647 {
1648 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1649 {
1650 if ((int)Insstart.col <= insstart_less)
1651 Insstart.col = 0;
1652 else
1653 Insstart.col -= insstart_less;
1654 }
1655 if ((int)ai_col <= insstart_less)
1656 ai_col = 0;
1657 else
1658 ai_col -= insstart_less;
1659 }
1660
1661 /*
1662 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1663 * If the number of characters before the cursor decreased, need to pop a
1664 * few characters from the replace stack.
1665 * If the number of characters before the cursor increased, need to push a
1666 * few NULs onto the replace stack.
1667 */
1668 if (REPLACE_NORMAL(State) && start_col >= 0)
1669 {
1670 while (start_col > (int)curwin->w_cursor.col)
1671 {
1672 replace_join(0); /* remove a NUL from the replace stack */
1673 --start_col;
1674 }
1675 while (start_col < (int)curwin->w_cursor.col || replaced)
1676 {
1677 replace_push(NUL);
1678 if (replaced)
1679 {
1680 replace_push(replaced);
1681 replaced = NUL;
1682 }
1683 ++start_col;
1684 }
1685 }
1686
1687#ifdef FEAT_VREPLACE
1688 /*
1689 * For VREPLACE mode, we also have to fix the replace stack. In this case
1690 * it is always possible because we backspace over the whole line and then
1691 * put it back again the way we wanted it.
1692 */
1693 if (State & VREPLACE_FLAG)
1694 {
1695 /* If orig_line didn't allocate, just return. At least we did the job,
1696 * even if you can't backspace. */
1697 if (orig_line == NULL)
1698 return;
1699
1700 /* Save new line */
1701 new_line = vim_strsave(ml_get_curline());
1702 if (new_line == NULL)
1703 return;
1704
1705 /* We only put back the new line up to the cursor */
1706 new_line[curwin->w_cursor.col] = NUL;
1707
1708 /* Put back original line */
1709 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1710 curwin->w_cursor.col = orig_col;
1711
1712 /* Backspace from cursor to start of line */
1713 backspace_until_column(0);
1714
1715 /* Insert new stuff into line again */
1716 ins_bytes(new_line);
1717
1718 vim_free(new_line);
1719 }
1720#endif
1721}
1722
1723/*
1724 * Truncate the space at the end of a line. This is to be used only in an
1725 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1726 * modes.
1727 */
1728 void
1729truncate_spaces(line)
1730 char_u *line;
1731{
1732 int i;
1733
1734 /* find start of trailing white space */
1735 for (i = (int)STRLEN(line) - 1; i >= 0 && vim_iswhite(line[i]); i--)
1736 {
1737 if (State & REPLACE_FLAG)
1738 replace_join(0); /* remove a NUL from the replace stack */
1739 }
1740 line[i + 1] = NUL;
1741}
1742
1743#if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \
1744 || defined(FEAT_COMMENTS) || defined(PROTO)
1745/*
1746 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1747 * modes correctly. May also be used when not in insert mode at all.
1748 */
1749 void
1750backspace_until_column(col)
1751 int col;
1752{
1753 while ((int)curwin->w_cursor.col > col)
1754 {
1755 curwin->w_cursor.col--;
1756 if (State & REPLACE_FLAG)
1757 replace_do_bs();
1758 else
1759 (void)del_char(FALSE);
1760 }
1761}
1762#endif
1763
1764#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1765/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001766 * CTRL-X pressed in Insert mode.
1767 */
1768 static void
1769ins_ctrl_x()
1770{
1771 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1772 * CTRL-V works like CTRL-N */
1773 if (ctrl_x_mode != CTRL_X_CMDLINE)
1774 {
1775 /* if the next ^X<> won't ADD nothing, then reset
1776 * compl_cont_status */
1777 if (compl_cont_status & CONT_N_ADDS)
1778 compl_cont_status = (compl_cont_status | CONT_INTRPT);
1779 else
1780 compl_cont_status = 0;
1781 /* We're not sure which CTRL-X mode it will be yet */
1782 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1783 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1784 edit_submode_pre = NULL;
1785 showmode();
1786 }
1787}
1788
1789/*
1790 * Return TRUE if the 'dict' or 'tsr' option can be used.
1791 */
1792 static int
1793has_compl_option(dict_opt)
1794 int dict_opt;
1795{
1796 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL)
1797 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
1798 {
1799 ctrl_x_mode = 0;
1800 edit_submode = NULL;
1801 msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
1802 : (char_u *)_("'thesaurus' option is empty"),
1803 hl_attr(HLF_E));
1804 if (emsg_silent == 0)
1805 {
1806 vim_beep();
1807 setcursor();
1808 out_flush();
1809 ui_delay(2000L, FALSE);
1810 }
1811 return FALSE;
1812 }
1813 return TRUE;
1814}
1815
1816/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
1818 * This depends on the current mode.
1819 */
1820 int
1821vim_is_ctrl_x_key(c)
1822 int c;
1823{
1824 /* Always allow ^R - let it's results then be checked */
1825 if (c == Ctrl_R)
1826 return TRUE;
1827
Bram Moolenaare3226be2005-12-18 22:10:00 +00001828 /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
1829 if (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
1830 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN))
1831 return TRUE;
1832
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 switch (ctrl_x_mode)
1834 {
1835 case 0: /* Not in any CTRL-X mode */
1836 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
1837 case CTRL_X_NOT_DEFINED_YET:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001838 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1840 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
1841 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
Bram Moolenaar488c6512005-08-11 20:09:58 +00001842 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
1843 || c == Ctrl_S || c == 's');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 case CTRL_X_SCROLL:
1845 return (c == Ctrl_Y || c == Ctrl_E);
1846 case CTRL_X_WHOLE_LINE:
1847 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
1848 case CTRL_X_FILES:
1849 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
1850 case CTRL_X_DICTIONARY:
1851 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
1852 case CTRL_X_THESAURUS:
1853 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
1854 case CTRL_X_TAGS:
1855 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
1856#ifdef FEAT_FIND_ID
1857 case CTRL_X_PATH_PATTERNS:
1858 return (c == Ctrl_P || c == Ctrl_N);
1859 case CTRL_X_PATH_DEFINES:
1860 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
1861#endif
1862 case CTRL_X_CMDLINE:
1863 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
1864 || c == Ctrl_X);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001865#ifdef FEAT_COMPL_FUNC
1866 case CTRL_X_FUNCTION:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001867 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaarf75a9632005-09-13 21:20:47 +00001868 case CTRL_X_OMNI:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001869 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaare344bea2005-09-01 20:46:49 +00001870#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00001871 case CTRL_X_SPELL:
1872 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 }
1874 EMSG(_(e_internal));
1875 return FALSE;
1876}
1877
1878/*
1879 * This is like ins_compl_add(), but if ic and inf are set, then the
1880 * case of the originally typed text is used, and the case of the completed
1881 * text is infered, ie this tries to work out what case you probably wanted
1882 * the rest of the word to be in -- webb
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001883 * TODO: make this work for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884 */
1885 int
Bram Moolenaar572cb562005-08-05 21:35:02 +00001886ins_compl_add_infercase(str, len, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 char_u *str;
1888 int len;
1889 char_u *fname;
1890 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00001891 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892{
1893 int has_lower = FALSE;
1894 int was_letter = FALSE;
1895 int idx;
1896
1897 if (p_ic && curbuf->b_p_inf && len < IOSIZE)
1898 {
1899 /* Infer case of completed part -- webb */
1900 /* Use IObuff, str would change text in buffer! */
Bram Moolenaarce0842a2005-07-18 21:58:11 +00001901 vim_strncpy(IObuff, str, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902
1903 /* Rule 1: Were any chars converted to lower? */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001904 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001906 if (islower(compl_orig_text[idx]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 {
1908 has_lower = TRUE;
1909 if (isupper(IObuff[idx]))
1910 {
1911 /* Rule 1 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001912 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
1914 break;
1915 }
1916 }
1917 }
1918
1919 /*
1920 * Rule 2: No lower case, 2nd consecutive letter converted to
1921 * upper case.
1922 */
1923 if (!has_lower)
1924 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001925 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001927 if (was_letter && isupper(compl_orig_text[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 && islower(IObuff[idx]))
1929 {
1930 /* Rule 2 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001931 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
1933 break;
1934 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001935 was_letter = isalpha(compl_orig_text[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 }
1937 }
1938
1939 /* Copy the original case of the part we typed */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001940 STRNCPY(IObuff, compl_orig_text, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941
Bram Moolenaar572cb562005-08-05 21:35:02 +00001942 return ins_compl_add(IObuff, len, fname, dir, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00001944 return ins_compl_add(str, len, fname, dir, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945}
1946
1947/*
1948 * Add a match to the list of matches.
1949 * If the given string is already in the list of completions, then return
1950 * FAIL, otherwise add it to the list and return OK. If there is an error,
Bram Moolenaar572cb562005-08-05 21:35:02 +00001951 * maybe because alloc() returns NULL, then RET_ERROR is returned -- webb.
1952 *
1953 * New:
1954 * If the given string is already in the list of completions, then return
1955 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
1956 * maybe because alloc() returns NULL, then FAIL is returned -- webb.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00001958 int
1959ins_compl_add(str, len, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 char_u *str;
1961 int len;
1962 char_u *fname;
1963 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00001964 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965{
Bram Moolenaar572cb562005-08-05 21:35:02 +00001966 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967
1968 ui_breakcheck();
1969 if (got_int)
Bram Moolenaar572cb562005-08-05 21:35:02 +00001970 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 if (len < 0)
1972 len = (int)STRLEN(str);
1973
1974 /*
1975 * If the same match is already present, don't add it.
1976 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001977 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001979 match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 do
1981 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00001982 if ( !(match->cp_flags & ORIGINAL_TEXT)
1983 && STRNCMP(match->cp_str, str, (size_t)len) == 0
1984 && match->cp_str[len] == NUL)
1985 return NOTDONE;
1986 match = match->cp_next;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001987 } while (match != NULL && match != compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 }
1989
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00001990 /* Remove any popup menu before changing the list of matches. */
1991 ins_compl_del_pum();
1992
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 /*
1994 * Allocate a new match structure.
1995 * Copy the values to the new match structure.
1996 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00001997 match = (compl_T *)alloc((unsigned)sizeof(compl_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998 if (match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00001999 return FAIL;
2000 match->cp_number = -1;
2001 if (flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002003 match->cp_number = 0;
2004 match->cp_str = compl_orig_text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002006 else if ((match->cp_str = vim_strnsave(str, len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 {
2008 vim_free(match);
Bram Moolenaar572cb562005-08-05 21:35:02 +00002009 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002010 }
2011 /* match-fname is:
Bram Moolenaar572cb562005-08-05 21:35:02 +00002012 * - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013 * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
2014 * - NULL otherwise. --Acevedo */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002015 if (fname && compl_curr_match && compl_curr_match->cp_fname
2016 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
2017 match->cp_fname = compl_curr_match->cp_fname;
2018 else if (fname && (match->cp_fname = vim_strsave(fname)) != NULL)
2019 flags |= FREE_FNAME;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 else
Bram Moolenaar572cb562005-08-05 21:35:02 +00002021 match->cp_fname = NULL;
2022 match->cp_flags = flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023
2024 /*
2025 * Link the new match structure in the list of matches.
2026 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002027 if (compl_first_match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002028 match->cp_next = match->cp_prev = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 else if (dir == FORWARD)
2030 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002031 match->cp_next = compl_curr_match->cp_next;
2032 match->cp_prev = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033 }
2034 else /* BACKWARD */
2035 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002036 match->cp_next = compl_curr_match;
2037 match->cp_prev = compl_curr_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002039 if (match->cp_next)
2040 match->cp_next->cp_prev = match;
2041 if (match->cp_prev)
2042 match->cp_prev->cp_next = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 else /* if there's nothing before, it is the first match */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002044 compl_first_match = match;
2045 compl_curr_match = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046
2047 return OK;
2048}
2049
2050/*
2051 * Add an array of matches to the list of matches.
2052 * Frees matches[].
2053 */
2054 static void
2055ins_compl_add_matches(num_matches, matches, dir)
2056 int num_matches;
2057 char_u **matches;
2058 int dir;
2059{
2060 int i;
2061 int add_r = OK;
2062 int ldir = dir;
2063
Bram Moolenaar572cb562005-08-05 21:35:02 +00002064 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065 if ((add_r = ins_compl_add(matches[i], -1, NULL, ldir, 0)) == OK)
2066 /* if dir was BACKWARD then honor it just once */
2067 ldir = FORWARD;
2068 FreeWild(num_matches, matches);
2069}
2070
2071/* Make the completion list cyclic.
2072 * Return the number of matches (excluding the original).
2073 */
2074 static int
2075ins_compl_make_cyclic()
2076{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002077 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078 int count = 0;
2079
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002080 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 {
2082 /*
2083 * Find the end of the list.
2084 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002085 match = compl_first_match;
2086 /* there's always an entry for the compl_orig_text, it doesn't count. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002087 while (match->cp_next != NULL && match->cp_next != compl_first_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002089 match = match->cp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090 ++count;
2091 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002092 match->cp_next = compl_first_match;
2093 compl_first_match->cp_prev = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 }
2095 return count;
2096}
2097
Bram Moolenaar9372a112005-12-06 19:59:18 +00002098/* "compl_match_array" points the currently displayed list of entries in the
2099 * popup menu. It is NULL when there is no popup menu. */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002100static char_u **compl_match_array = NULL;
2101static int compl_match_arraysize;
2102
2103/*
2104 * Update the screen and when there is any scrolling remove the popup menu.
2105 */
2106 static void
2107ins_compl_upd_pum()
2108{
2109 int h;
2110
2111 if (compl_match_array != NULL)
2112 {
2113 h = curwin->w_cline_height;
2114 update_screen(0);
2115 if (h != curwin->w_cline_height)
2116 ins_compl_del_pum();
2117 }
2118}
2119
2120/*
2121 * Remove any popup menu.
2122 */
2123 static void
2124ins_compl_del_pum()
2125{
2126 if (compl_match_array != NULL)
2127 {
2128 pum_undisplay();
2129 vim_free(compl_match_array);
2130 compl_match_array = NULL;
2131 }
2132}
2133
2134/*
2135 * Return TRUE if the popup menu should be displayed.
2136 */
2137 static int
2138pum_wanted()
2139{
2140 compl_T *compl;
2141 int i;
2142
2143 /* 'completeopt' must contain "menu" */
2144 if (*p_cot == NUL)
2145 return FALSE;
2146
2147 /* The display looks bad on a B&W display. */
2148 if (t_colors < 8
2149#ifdef FEAT_GUI
2150 && !gui.in_use
2151#endif
2152 )
2153 return FALSE;
2154
2155 /* Don't display the popup menu if there are no matches or there is only
2156 * one (ignoring the original text). */
2157 compl = compl_first_match;
2158 i = 0;
2159 do
2160 {
2161 if (compl == NULL
2162 || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
2163 break;
2164 compl = compl->cp_next;
2165 } while (compl != compl_first_match);
2166
2167 return (i >= 2);
2168}
2169
2170/*
2171 * Show the popup menu for the list of matches.
2172 */
2173 static void
2174ins_compl_show_pum()
2175{
2176 compl_T *compl;
2177 int i;
2178 int cur = -1;
2179 colnr_T col;
2180
2181 if (!pum_wanted())
2182 return;
2183
2184 /* Update the screen before drawing the popup menu over it. */
2185 update_screen(0);
2186
2187 if (compl_match_array == NULL)
2188 {
2189 /* Need to build the popup menu list. */
2190 compl_match_arraysize = 0;
2191 compl = compl_first_match;
2192 do
2193 {
2194 if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
2195 ++compl_match_arraysize;
2196 compl = compl->cp_next;
2197 } while (compl != NULL && compl != compl_first_match);
2198 compl_match_array = (char_u **)alloc((unsigned)(sizeof(char_u **)
2199 * compl_match_arraysize));
2200 if (compl_match_array != NULL)
2201 {
2202 i = 0;
2203 compl = compl_first_match;
2204 do
2205 {
2206 if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
2207 {
2208 if (compl == compl_shown_match)
2209 cur = i;
2210 compl_match_array[i++] = compl->cp_str;
2211 }
2212 compl = compl->cp_next;
2213 } while (compl != NULL && compl != compl_first_match);
2214 }
2215 }
2216 else
2217 {
2218 /* popup menu already exists, only need to find the current item.*/
2219 i = 0;
2220 compl = compl_first_match;
2221 do
2222 {
2223 if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
2224 {
2225 if (compl == compl_shown_match)
2226 {
2227 cur = i;
2228 break;
2229 }
2230 ++i;
2231 }
2232 compl = compl->cp_next;
2233 } while (compl != NULL && compl != compl_first_match);
2234 }
2235
2236 if (compl_match_array != NULL)
2237 {
2238 /* Compute the screen column of the start of the completed text.
2239 * Use the cursor to get all wrapping and other settings right. */
2240 col = curwin->w_cursor.col;
2241 curwin->w_cursor.col = compl_col;
2242 validate_cursor_col();
2243 pum_display(compl_match_array, compl_match_arraysize, cur,
2244 curwin->w_cline_row + W_WINROW(curwin),
2245 curwin->w_cline_height,
2246 curwin->w_wcol + W_WINCOL(curwin));
2247 curwin->w_cursor.col = col;
2248 }
2249}
2250
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251#define DICT_FIRST (1) /* use just first element in "dict" */
2252#define DICT_EXACT (2) /* "dict" is the exact name of a file */
2253/*
2254 * Add any identifiers that match the given pattern to the list of
2255 * completions.
2256 */
2257 static void
2258ins_compl_dictionaries(dict, pat, dir, flags, thesaurus)
2259 char_u *dict;
2260 char_u *pat;
2261 int dir;
2262 int flags;
2263 int thesaurus;
2264{
2265 char_u *ptr;
2266 char_u *buf;
2267 FILE *fp;
2268 regmatch_T regmatch;
2269 int add_r;
2270 char_u **files;
2271 int count;
2272 int i;
2273 int save_p_scs;
2274
2275 buf = alloc(LSIZE);
2276 /* If 'infercase' is set, don't use 'smartcase' here */
2277 save_p_scs = p_scs;
2278 if (curbuf->b_p_inf)
2279 p_scs = FALSE;
2280 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
2281 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2282 regmatch.rm_ic = ignorecase(pat);
2283 while (buf != NULL && regmatch.regprog != NULL && *dict != NUL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002284 && !got_int && !compl_interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 {
2286 /* copy one dictionary file name into buf */
2287 if (flags == DICT_EXACT)
2288 {
2289 count = 1;
2290 files = &dict;
2291 }
2292 else
2293 {
2294 /* Expand wildcards in the dictionary name, but do not allow
2295 * backticks (for security, the 'dict' option may have been set in
2296 * a modeline). */
2297 copy_option_part(&dict, buf, LSIZE, ",");
2298 if (vim_strchr(buf, '`') != NULL
2299 || expand_wildcards(1, &buf, &count, &files,
2300 EW_FILE|EW_SILENT) != OK)
2301 count = 0;
2302 }
2303
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002304 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 {
2306 fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
2307 if (flags != DICT_EXACT)
2308 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002309 vim_snprintf((char *)IObuff, IOSIZE,
2310 _("Scanning dictionary: %s"), (char *)files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2312 }
2313
2314 if (fp != NULL)
2315 {
2316 /*
2317 * Read dictionary file line by line.
2318 * Check each line for a match.
2319 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002320 while (!got_int && !compl_interrupted
2321 && !vim_fgets(buf, LSIZE, fp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 {
2323 ptr = buf;
2324 while (vim_regexec(&regmatch, buf, (colnr_T)(ptr - buf)))
2325 {
2326 ptr = regmatch.startp[0];
2327 ptr = find_word_end(ptr);
2328 add_r = ins_compl_add_infercase(regmatch.startp[0],
2329 (int)(ptr - regmatch.startp[0]),
2330 files[i], dir, 0);
2331 if (thesaurus)
2332 {
2333 char_u *wstart;
2334
2335 /*
2336 * Add the other matches on the line
2337 */
2338 while (!got_int)
2339 {
2340 /* Find start of the next word. Skip white
2341 * space and punctuation. */
2342 ptr = find_word_start(ptr);
2343 if (*ptr == NUL || *ptr == NL)
2344 break;
2345 wstart = ptr;
2346
2347 /* Find end of the word and add it. */
2348#ifdef FEAT_MBYTE
2349 if (has_mbyte)
2350 /* Japanese words may have characters in
2351 * different classes, only separate words
2352 * with single-byte non-word characters. */
2353 while (*ptr != NUL)
2354 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002355 int l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356
2357 if (l < 2 && !vim_iswordc(*ptr))
2358 break;
2359 ptr += l;
2360 }
2361 else
2362#endif
2363 ptr = find_word_end(ptr);
2364 add_r = ins_compl_add_infercase(wstart,
2365 (int)(ptr - wstart), files[i], dir, 0);
2366 }
2367 }
2368 if (add_r == OK)
2369 /* if dir was BACKWARD then honor it just once */
2370 dir = FORWARD;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002371 else if (add_r == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 break;
2373 /* avoid expensive call to vim_regexec() when at end
2374 * of line */
2375 if (*ptr == '\n' || got_int)
2376 break;
2377 }
2378 line_breakcheck();
Bram Moolenaar572cb562005-08-05 21:35:02 +00002379 ins_compl_check_keys(50);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 }
2381 fclose(fp);
2382 }
2383 }
2384 if (flags != DICT_EXACT)
2385 FreeWild(count, files);
2386 if (flags)
2387 break;
2388 }
2389 p_scs = save_p_scs;
2390 vim_free(regmatch.regprog);
2391 vim_free(buf);
2392}
2393
2394/*
2395 * Find the start of the next word.
2396 * Returns a pointer to the first char of the word. Also stops at a NUL.
2397 */
2398 char_u *
2399find_word_start(ptr)
2400 char_u *ptr;
2401{
2402#ifdef FEAT_MBYTE
2403 if (has_mbyte)
2404 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002405 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 else
2407#endif
2408 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2409 ++ptr;
2410 return ptr;
2411}
2412
2413/*
2414 * Find the end of the word. Assumes it starts inside a word.
2415 * Returns a pointer to just after the word.
2416 */
2417 char_u *
2418find_word_end(ptr)
2419 char_u *ptr;
2420{
2421#ifdef FEAT_MBYTE
2422 int start_class;
2423
2424 if (has_mbyte)
2425 {
2426 start_class = mb_get_class(ptr);
2427 if (start_class > 1)
2428 while (*ptr != NUL)
2429 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002430 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431 if (mb_get_class(ptr) != start_class)
2432 break;
2433 }
2434 }
2435 else
2436#endif
2437 while (vim_iswordc(*ptr))
2438 ++ptr;
2439 return ptr;
2440}
2441
2442/*
2443 * Free the list of completions
2444 */
2445 static void
2446ins_compl_free()
2447{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002448 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002450 vim_free(compl_pattern);
2451 compl_pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002453 if (compl_first_match == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 return;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002455
2456 ins_compl_del_pum();
2457 pum_clear();
2458
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002459 compl_curr_match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 do
2461 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002462 match = compl_curr_match;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002463 compl_curr_match = compl_curr_match->cp_next;
2464 vim_free(match->cp_str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 /* several entries may use the same fname, free it just once. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002466 if (match->cp_flags & FREE_FNAME)
2467 vim_free(match->cp_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 vim_free(match);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002469 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
2470 compl_first_match = compl_curr_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471}
2472
2473 static void
2474ins_compl_clear()
2475{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002476 compl_cont_status = 0;
2477 compl_started = FALSE;
2478 compl_matches = 0;
2479 vim_free(compl_pattern);
2480 compl_pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 save_sm = -1;
2482 edit_submode_extra = NULL;
2483}
2484
2485/*
2486 * Prepare for Insert mode completion, or stop it.
Bram Moolenaar572cb562005-08-05 21:35:02 +00002487 * Called just after typing a character in Insert mode.
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002488 * Returns TRUE when the character is not to be inserted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002490 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491ins_compl_prep(c)
2492 int c;
2493{
2494 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 int temp;
2496 int want_cindent;
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002497 int retval = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498
2499 /* Forget any previous 'special' messages if this is actually
2500 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
2501 */
2502 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
2503 edit_submode_extra = NULL;
2504
2505 /* Ignore end of Select mode mapping */
2506 if (c == K_SELECT)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002507 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508
2509 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
2510 {
2511 /*
2512 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
2513 * it will be yet. Now we decide.
2514 */
2515 switch (c)
2516 {
2517 case Ctrl_E:
2518 case Ctrl_Y:
2519 ctrl_x_mode = CTRL_X_SCROLL;
2520 if (!(State & REPLACE_FLAG))
2521 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
2522 else
2523 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
2524 edit_submode_pre = NULL;
2525 showmode();
2526 break;
2527 case Ctrl_L:
2528 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2529 break;
2530 case Ctrl_F:
2531 ctrl_x_mode = CTRL_X_FILES;
2532 break;
2533 case Ctrl_K:
2534 ctrl_x_mode = CTRL_X_DICTIONARY;
2535 break;
2536 case Ctrl_R:
2537 /* Simply allow ^R to happen without affecting ^X mode */
2538 break;
2539 case Ctrl_T:
2540 ctrl_x_mode = CTRL_X_THESAURUS;
2541 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002542#ifdef FEAT_COMPL_FUNC
2543 case Ctrl_U:
2544 ctrl_x_mode = CTRL_X_FUNCTION;
2545 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002546 case Ctrl_O:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002547 ctrl_x_mode = CTRL_X_OMNI;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002548 break;
Bram Moolenaare344bea2005-09-01 20:46:49 +00002549#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002550 case 's':
2551 case Ctrl_S:
2552 ctrl_x_mode = CTRL_X_SPELL;
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00002553#ifdef FEAT_SYN_HL
2554 spell_back_to_badword();
2555#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002556 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 case Ctrl_RSB:
2558 ctrl_x_mode = CTRL_X_TAGS;
2559 break;
2560#ifdef FEAT_FIND_ID
2561 case Ctrl_I:
2562 case K_S_TAB:
2563 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
2564 break;
2565 case Ctrl_D:
2566 ctrl_x_mode = CTRL_X_PATH_DEFINES;
2567 break;
2568#endif
2569 case Ctrl_V:
2570 case Ctrl_Q:
2571 ctrl_x_mode = CTRL_X_CMDLINE;
2572 break;
2573 case Ctrl_P:
2574 case Ctrl_N:
2575 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
2576 * just started ^X mode, or there were enough ^X's to cancel
2577 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
2578 * do normal expansion when interrupting a different mode (say
2579 * ^X^F^X^P or ^P^X^X^P, see below)
2580 * nothing changes if interrupting mode 0, (eg, the flag
2581 * doesn't change when going to ADDING mode -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002582 if (!(compl_cont_status & CONT_INTRPT))
2583 compl_cont_status |= CONT_LOCAL;
2584 else if (compl_cont_mode != 0)
2585 compl_cont_status &= ~CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 /* FALLTHROUGH */
2587 default:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002588 /* If we have typed at least 2 ^X's... for modes != 0, we set
2589 * compl_cont_status = 0 (eg, as if we had just started ^X
2590 * mode).
2591 * For mode 0, we set "compl_cont_mode" to an impossible
2592 * value, in both cases ^X^X can be used to restart the same
2593 * mode (avoiding ADDING mode).
2594 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
2595 * 'complete' and local ^P expansions respectively.
2596 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
2597 * mode -- Acevedo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 if (c == Ctrl_X)
2599 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002600 if (compl_cont_mode != 0)
2601 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002603 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604 }
2605 ctrl_x_mode = 0;
2606 edit_submode = NULL;
2607 showmode();
2608 break;
2609 }
2610 }
2611 else if (ctrl_x_mode != 0)
2612 {
2613 /* We're already in CTRL-X mode, do we stay in it? */
2614 if (!vim_is_ctrl_x_key(c))
2615 {
2616 if (ctrl_x_mode == CTRL_X_SCROLL)
2617 ctrl_x_mode = 0;
2618 else
2619 ctrl_x_mode = CTRL_X_FINISHED;
2620 edit_submode = NULL;
2621 }
2622 showmode();
2623 }
2624
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002625 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 {
2627 /* Show error message from attempted keyword completion (probably
2628 * 'Pattern not found') until another key is hit, then go back to
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002629 * showing what mode we are in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630 showmode();
2631 if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R)
2632 || ctrl_x_mode == CTRL_X_FINISHED)
2633 {
2634 /* Get here when we have finished typing a sequence of ^N and
2635 * ^P or other completion characters in CTRL-X mode. Free up
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002636 * memory that was used, and make sure we can redo the insert. */
2637 if (compl_curr_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002639 char_u *p;
2640
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 /*
2642 * If any of the original typed text has been changed,
2643 * eg when ignorecase is set, we must add back-spaces to
2644 * the redo buffer. We add as few as necessary to delete
2645 * just the part of the original text that has changed.
2646 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002647 ptr = compl_curr_match->cp_str;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002648 p = compl_orig_text;
2649 while (*p && *p == *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002651 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 ++ptr;
2653 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002654 for (temp = 0; p[temp]; ++temp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 AppendCharToRedobuff(K_BS);
2656 AppendToRedobuffLit(ptr);
2657 }
2658
2659#ifdef FEAT_CINDENT
2660 want_cindent = (can_cindent && cindent_on());
2661#endif
2662 /*
2663 * When completing whole lines: fix indent for 'cindent'.
2664 * Otherwise, break line if it's too long.
2665 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002666 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 {
2668#ifdef FEAT_CINDENT
2669 /* re-indent the current line */
2670 if (want_cindent)
2671 {
2672 do_c_expr_indent();
2673 want_cindent = FALSE; /* don't do it again */
2674 }
2675#endif
2676 }
2677 else
2678 {
2679 /* put the cursor on the last char, for 'tw' formatting */
2680 curwin->w_cursor.col--;
2681 if (stop_arrow() == OK)
2682 insertchar(NUL, 0, -1);
2683 curwin->w_cursor.col++;
2684 }
2685
2686 auto_format(FALSE, TRUE);
2687
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002688 /* if the popup menu is displayed hitting Enter means accepting
2689 * the selection without inserting anything. */
2690 if ((c == CAR || c == K_KENTER || c == NL) && pum_visible())
2691 retval = TRUE;
2692
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 ins_compl_free();
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002694 compl_started = FALSE;
2695 compl_matches = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 msg_clr_cmdline(); /* necessary for "noshowmode" */
2697 ctrl_x_mode = 0;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002698 if (save_sm >= 0)
2699 p_sm = save_sm;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 if (edit_submode != NULL)
2701 {
2702 edit_submode = NULL;
2703 showmode();
2704 }
2705
2706#ifdef FEAT_CINDENT
2707 /*
2708 * Indent now if a key was typed that is in 'cinkeys'.
2709 */
2710 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
2711 do_c_expr_indent();
2712#endif
2713 }
2714 }
2715
2716 /* reset continue_* if we left expansion-mode, if we stay they'll be
2717 * (re)set properly in ins_complete() */
2718 if (!vim_is_ctrl_x_key(c))
2719 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002720 compl_cont_status = 0;
2721 compl_cont_mode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002723
2724 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725}
2726
2727/*
2728 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
2729 * (depending on flag) starting from buf and looking for a non-scanned
2730 * buffer (other than curbuf). curbuf is special, if it is called with
2731 * buf=curbuf then it has to be the first call for a given flag/expansion.
2732 *
2733 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
2734 */
2735 static buf_T *
2736ins_compl_next_buf(buf, flag)
2737 buf_T *buf;
2738 int flag;
2739{
2740#ifdef FEAT_WINDOWS
2741 static win_T *wp;
2742#endif
2743
2744 if (flag == 'w') /* just windows */
2745 {
2746#ifdef FEAT_WINDOWS
2747 if (buf == curbuf) /* first call for this flag/expansion */
2748 wp = curwin;
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00002749 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750 && wp->w_buffer->b_scanned)
2751 ;
2752 buf = wp->w_buffer;
2753#else
2754 buf = curbuf;
2755#endif
2756 }
2757 else
2758 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
2759 * (unlisted buffers)
2760 * When completing whole lines skip unloaded buffers. */
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00002761 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762 && ((flag == 'U'
2763 ? buf->b_p_bl
2764 : (!buf->b_p_bl
2765 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
2766 || buf->b_scanned
2767 || (buf->b_ml.ml_mfp == NULL
2768 && ctrl_x_mode == CTRL_X_WHOLE_LINE)))
2769 ;
2770 return buf;
2771}
2772
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002773#ifdef FEAT_COMPL_FUNC
Bram Moolenaare344bea2005-09-01 20:46:49 +00002774static int expand_by_function __ARGS((int type, char_u *base, char_u ***matches));
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002775
2776/*
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002777 * Execute user defined complete function 'completefunc' or 'omnifunc', and
Bram Moolenaare344bea2005-09-01 20:46:49 +00002778 * get matches in "matches".
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002779 * Return value is number of matches.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002780 */
2781 static int
Bram Moolenaare344bea2005-09-01 20:46:49 +00002782expand_by_function(type, base, matches)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00002783 int type; /* CTRL_X_OMNI or CTRL_X_FUNCTION */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002784 char_u *base;
2785 char_u ***matches;
2786{
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002787 list_T *matchlist;
Bram Moolenaare344bea2005-09-01 20:46:49 +00002788 char_u *args[2];
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002789 listitem_T *li;
2790 garray_T ga;
2791 char_u *p;
Bram Moolenaare344bea2005-09-01 20:46:49 +00002792 char_u *funcname;
2793 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002794
Bram Moolenaare344bea2005-09-01 20:46:49 +00002795 funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
2796 if (*funcname == NUL)
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002797 return 0;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002798
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002799 /* Call 'completefunc' to obtain the list of matches. */
2800 args[0] = (char_u *)"0";
Bram Moolenaare344bea2005-09-01 20:46:49 +00002801 args[1] = base;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002802
Bram Moolenaare344bea2005-09-01 20:46:49 +00002803 pos = curwin->w_cursor;
2804 matchlist = call_func_retlist(funcname, 2, args, FALSE);
2805 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002806 if (matchlist == NULL)
2807 return 0;
2808
2809 /* Go through the List with matches and put them in an array. */
2810 ga_init2(&ga, (int)sizeof(char_u *), 8);
2811 for (li = matchlist->lv_first; li != NULL; li = li->li_next)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002812 {
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002813 p = get_tv_string_chk(&li->li_tv);
2814 if (p != NULL && *p != NUL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002815 {
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002816 if (ga_grow(&ga, 1) == FAIL)
2817 break;
2818 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strsave(p);
2819 ++ga.ga_len;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002820 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002821 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002822
2823 list_unref(matchlist);
2824 *matches = (char_u **)ga.ga_data;
2825 return ga.ga_len;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002826}
2827#endif /* FEAT_COMPL_FUNC */
2828
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002829/*
2830 * Get the next expansion(s), using "compl_pattern".
2831 * The search starts at position "ini" in curbuf and in the direction dir.
2832 * When "compl_started" is FALSE start at that position, otherwise
2833 * continue where we stopped searching before.
2834 * This may return before finding all the matches.
2835 * Return the total number of matches or -1 if still unknown -- Acevedo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836 */
2837 static int
2838ins_compl_get_exp(ini, dir)
2839 pos_T *ini;
2840 int dir;
2841{
2842 static pos_T first_match_pos;
2843 static pos_T last_match_pos;
2844 static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002845 static int found_all = FALSE; /* Found all matches of a
2846 certain type. */
2847 static buf_T *ins_buf = NULL; /* buffer being scanned */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848
Bram Moolenaar572cb562005-08-05 21:35:02 +00002849 pos_T *pos;
2850 char_u **matches;
2851 int save_p_scs;
2852 int save_p_ws;
2853 int save_p_ic;
2854 int i;
2855 int num_matches;
2856 int len;
2857 int found_new_match;
2858 int type = ctrl_x_mode;
2859 char_u *ptr;
2860 char_u *dict = NULL;
2861 int dict_f = 0;
2862 compl_T *old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002864 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002865 {
2866 for (ins_buf = firstbuf; ins_buf != NULL; ins_buf = ins_buf->b_next)
2867 ins_buf->b_scanned = 0;
2868 found_all = FALSE;
2869 ins_buf = curbuf;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002870 e_cpt = (compl_cont_status & CONT_LOCAL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002871 ? (char_u *)"." : curbuf->b_p_cpt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 last_match_pos = first_match_pos = *ini;
2873 }
2874
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002875 old_match = compl_curr_match; /* remember the last current match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 pos = (dir == FORWARD) ? &last_match_pos : &first_match_pos;
2877 /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
2878 for (;;)
2879 {
2880 found_new_match = FAIL;
2881
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002882 /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883 * or if found_all says this entry is done. For ^X^L only use the
2884 * entries from 'complete' that look in loaded buffers. */
2885 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002886 && (!compl_started || found_all))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 {
2888 found_all = FALSE;
2889 while (*e_cpt == ',' || *e_cpt == ' ')
2890 e_cpt++;
2891 if (*e_cpt == '.' && !curbuf->b_scanned)
2892 {
2893 ins_buf = curbuf;
2894 first_match_pos = *ini;
2895 /* So that ^N can match word immediately after cursor */
2896 if (ctrl_x_mode == 0)
2897 dec(&first_match_pos);
2898 last_match_pos = first_match_pos;
2899 type = 0;
2900 }
2901 else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
2902 && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
2903 {
2904 /* Scan a buffer, but not the current one. */
2905 if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
2906 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002907 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908 first_match_pos.col = last_match_pos.col = 0;
2909 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
2910 last_match_pos.lnum = 0;
2911 type = 0;
2912 }
2913 else /* unloaded buffer, scan like dictionary */
2914 {
2915 found_all = TRUE;
2916 if (ins_buf->b_fname == NULL)
2917 continue;
2918 type = CTRL_X_DICTIONARY;
2919 dict = ins_buf->b_fname;
2920 dict_f = DICT_EXACT;
2921 }
Bram Moolenaar555b2802005-05-19 21:08:39 +00002922 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 ins_buf->b_fname == NULL
2924 ? buf_spname(ins_buf)
2925 : ins_buf->b_sfname == NULL
2926 ? (char *)ins_buf->b_fname
2927 : (char *)ins_buf->b_sfname);
2928 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2929 }
2930 else if (*e_cpt == NUL)
2931 break;
2932 else
2933 {
2934 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2935 type = -1;
2936 else if (*e_cpt == 'k' || *e_cpt == 's')
2937 {
2938 if (*e_cpt == 'k')
2939 type = CTRL_X_DICTIONARY;
2940 else
2941 type = CTRL_X_THESAURUS;
2942 if (*++e_cpt != ',' && *e_cpt != NUL)
2943 {
2944 dict = e_cpt;
2945 dict_f = DICT_FIRST;
2946 }
2947 }
2948#ifdef FEAT_FIND_ID
2949 else if (*e_cpt == 'i')
2950 type = CTRL_X_PATH_PATTERNS;
2951 else if (*e_cpt == 'd')
2952 type = CTRL_X_PATH_DEFINES;
2953#endif
2954 else if (*e_cpt == ']' || *e_cpt == 't')
2955 {
2956 type = CTRL_X_TAGS;
2957 sprintf((char*)IObuff, _("Scanning tags."));
2958 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2959 }
2960 else
2961 type = -1;
2962
2963 /* in any case e_cpt is advanced to the next entry */
2964 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
2965
2966 found_all = TRUE;
2967 if (type == -1)
2968 continue;
2969 }
2970 }
2971
2972 switch (type)
2973 {
2974 case -1:
2975 break;
2976#ifdef FEAT_FIND_ID
2977 case CTRL_X_PATH_PATTERNS:
2978 case CTRL_X_PATH_DEFINES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002979 find_pattern_in_path(compl_pattern, dir,
2980 (int)STRLEN(compl_pattern), FALSE, FALSE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 (type == CTRL_X_PATH_DEFINES
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002982 && !(compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
2984 (linenr_T)1, (linenr_T)MAXLNUM);
2985 break;
2986#endif
2987
2988 case CTRL_X_DICTIONARY:
2989 case CTRL_X_THESAURUS:
2990 ins_compl_dictionaries(
2991 dict ? dict
2992 : (type == CTRL_X_THESAURUS
2993 ? (*curbuf->b_p_tsr == NUL
2994 ? p_tsr
2995 : curbuf->b_p_tsr)
2996 : (*curbuf->b_p_dict == NUL
2997 ? p_dict
2998 : curbuf->b_p_dict)),
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002999 compl_pattern, dir,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 dict ? dict_f : 0, type == CTRL_X_THESAURUS);
3001 dict = NULL;
3002 break;
3003
3004 case CTRL_X_TAGS:
3005 /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
3006 save_p_ic = p_ic;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003007 p_ic = ignorecase(compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008
3009 /* Find up to TAG_MANY matches. Avoids that an enourmous number
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003010 * of matches is found when compl_pattern is empty */
3011 if (find_tags(compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
3013 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
3014 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3015 {
3016 ins_compl_add_matches(num_matches, matches, dir);
3017 }
3018 p_ic = save_p_ic;
3019 break;
3020
3021 case CTRL_X_FILES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003022 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
3024 {
3025
3026 /* May change home directory back to "~". */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003027 tilde_replace(compl_pattern, num_matches, matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 ins_compl_add_matches(num_matches, matches, dir);
3029 }
3030 break;
3031
3032 case CTRL_X_CMDLINE:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003033 if (expand_cmdline(&compl_xp, compl_pattern,
3034 (int)STRLEN(compl_pattern),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 &num_matches, &matches) == EXPAND_OK)
3036 ins_compl_add_matches(num_matches, matches, dir);
3037 break;
3038
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003039#ifdef FEAT_COMPL_FUNC
3040 case CTRL_X_FUNCTION:
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003041 case CTRL_X_OMNI:
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00003042 num_matches = expand_by_function(type, compl_pattern, &matches);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003043 if (num_matches > 0)
3044 ins_compl_add_matches(num_matches, matches, dir);
3045 break;
3046#endif
3047
Bram Moolenaar488c6512005-08-11 20:09:58 +00003048 case CTRL_X_SPELL:
3049#ifdef FEAT_SYN_HL
3050 num_matches = expand_spelling(first_match_pos.lnum,
3051 first_match_pos.col, compl_pattern, &matches);
3052 if (num_matches > 0)
3053 ins_compl_add_matches(num_matches, matches, dir);
3054#endif
3055 break;
3056
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 default: /* normal ^P/^N and ^X^L */
3058 /*
3059 * If 'infercase' is set, don't use 'smartcase' here
3060 */
3061 save_p_scs = p_scs;
3062 if (ins_buf->b_p_inf)
3063 p_scs = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003064
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065 /* buffers other than curbuf are scanned from the beginning or the
3066 * end but never from the middle, thus setting nowrapscan in this
3067 * buffers is a good idea, on the other hand, we always set
3068 * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
3069 save_p_ws = p_ws;
3070 if (ins_buf != curbuf)
3071 p_ws = FALSE;
3072 else if (*e_cpt == '.')
3073 p_ws = TRUE;
3074 for (;;)
3075 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003076 int flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003078 /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that
3079 * has added a word that was at the beginning of the line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080 if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003081 || (compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082 found_new_match = search_for_exact_line(ins_buf, pos,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003083 dir, compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 else
3085 found_new_match = searchit(NULL, ins_buf, pos, dir,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003086 compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087 RE_LAST);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003088 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003090 /* set compl_started even on fail */
3091 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 first_match_pos = *pos;
3093 last_match_pos = *pos;
3094 }
3095 else if (first_match_pos.lnum == last_match_pos.lnum
3096 && first_match_pos.col == last_match_pos.col)
3097 found_new_match = FAIL;
3098 if (found_new_match == FAIL)
3099 {
3100 if (ins_buf == curbuf)
3101 found_all = TRUE;
3102 break;
3103 }
3104
3105 /* when ADDING, the text before the cursor matches, skip it */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003106 if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 && ini->lnum == pos->lnum
3108 && ini->col == pos->col)
3109 continue;
3110 ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
3111 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3112 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003113 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 {
3115 if (pos->lnum >= ins_buf->b_ml.ml_line_count)
3116 continue;
3117 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3118 if (!p_paste)
3119 ptr = skipwhite(ptr);
3120 }
3121 len = (int)STRLEN(ptr);
3122 }
3123 else
3124 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003125 char_u *tmp_ptr = ptr;
3126
3127 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003129 tmp_ptr += compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 /* Skip if already inside a word. */
3131 if (vim_iswordp(tmp_ptr))
3132 continue;
3133 /* Find start of next word. */
3134 tmp_ptr = find_word_start(tmp_ptr);
3135 }
3136 /* Find end of this word. */
3137 tmp_ptr = find_word_end(tmp_ptr);
3138 len = (int)(tmp_ptr - ptr);
3139
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003140 if ((compl_cont_status & CONT_ADDING)
3141 && len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 {
3143 if (pos->lnum < ins_buf->b_ml.ml_line_count)
3144 {
3145 /* Try next line, if any. the new word will be
3146 * "join" as if the normal command "J" was used.
3147 * IOSIZE is always greater than
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003148 * compl_length, so the next STRNCPY always
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 * works -- Acevedo */
3150 STRNCPY(IObuff, ptr, len);
3151 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
3152 tmp_ptr = ptr = skipwhite(ptr);
3153 /* Find start of next word. */
3154 tmp_ptr = find_word_start(tmp_ptr);
3155 /* Find end of next word. */
3156 tmp_ptr = find_word_end(tmp_ptr);
3157 if (tmp_ptr > ptr)
3158 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003159 if (*ptr != ')' && IObuff[len - 1] != TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003161 if (IObuff[len - 1] != ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162 IObuff[len++] = ' ';
3163 /* IObuf =~ "\k.* ", thus len >= 2 */
3164 if (p_js
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003165 && (IObuff[len - 2] == '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166 || (vim_strchr(p_cpo, CPO_JOINSP)
3167 == NULL
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003168 && (IObuff[len - 2] == '?'
3169 || IObuff[len - 2] == '!'))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 IObuff[len++] = ' ';
3171 }
3172 /* copy as much as posible of the new word */
3173 if (tmp_ptr - ptr >= IOSIZE - len)
3174 tmp_ptr = ptr + IOSIZE - len - 1;
3175 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3176 len += (int)(tmp_ptr - ptr);
Bram Moolenaar572cb562005-08-05 21:35:02 +00003177 flags |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 }
3179 IObuff[len] = NUL;
3180 ptr = IObuff;
3181 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003182 if (len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183 continue;
3184 }
3185 }
3186 if (ins_compl_add_infercase(ptr, len,
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003187 ins_buf == curbuf ? NULL : ins_buf->b_sfname,
Bram Moolenaar572cb562005-08-05 21:35:02 +00003188 dir, flags) != NOTDONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 {
3190 found_new_match = OK;
3191 break;
3192 }
3193 }
3194 p_scs = save_p_scs;
3195 p_ws = save_p_ws;
3196 }
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003197
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003198 /* check if compl_curr_match has changed, (e.g. other type of
3199 * expansion added somenthing) */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003200 if (type != 0 && compl_curr_match != old_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201 found_new_match = OK;
3202
3203 /* break the loop for specialized modes (use 'complete' just for the
3204 * generic ctrl_x_mode == 0) or when we've found a new match */
3205 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003206 || found_new_match != FAIL)
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003207 {
3208 if (got_int)
3209 break;
3210 if (pum_wanted() && type != -1)
3211 /* Fill the popup menu as soon as possible. */
3212 ins_compl_check_keys(0);
3213 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
3214 || compl_interrupted)
3215 break;
3216 compl_started = TRUE;
3217 }
3218 else
3219 {
3220 /* Mark a buffer scanned when it has been scanned completely */
3221 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
3222 ins_buf->b_scanned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003224 compl_started = FALSE;
3225 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003227 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228
3229 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
3230 && *e_cpt == NUL) /* Got to end of 'complete' */
3231 found_new_match = FAIL;
3232
3233 i = -1; /* total of matches, unknown */
3234 if (found_new_match == FAIL
3235 || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
3236 i = ins_compl_make_cyclic();
3237
3238 /* If several matches were added (FORWARD) or the search failed and has
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003239 * just been made cyclic then we have to move compl_curr_match to the next
3240 * or previous entry (if any) -- Acevedo */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003241 compl_curr_match = dir == FORWARD ? old_match->cp_next : old_match->cp_prev;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003242 if (compl_curr_match == NULL)
3243 compl_curr_match = old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 return i;
3245}
3246
3247/* Delete the old text being completed. */
3248 static void
3249ins_compl_delete()
3250{
3251 int i;
3252
3253 /*
3254 * In insert mode: Delete the typed part.
3255 * In replace mode: Put the old characters back, if any.
3256 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003257 i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 backspace_until_column(i);
3259 changed_cline_bef_curs();
3260}
3261
3262/* Insert the new text being completed. */
3263 static void
3264ins_compl_insert()
3265{
Bram Moolenaar572cb562005-08-05 21:35:02 +00003266 ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267}
3268
3269/*
3270 * Fill in the next completion in the current direction.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003271 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
3272 * get more completions. If it is FALSE, then we just do nothing when there
3273 * are no more completions in a given direction. The latter case is used when
3274 * we are still in the middle of finding completions, to allow browsing
3275 * through the ones found so far.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276 * Return the total number of matches, or -1 if still unknown -- webb.
3277 *
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003278 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
3279 * compl_shown_match here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280 *
3281 * Note that this function may be called recursively once only. First with
Bram Moolenaar572cb562005-08-05 21:35:02 +00003282 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
3283 * calls this function with "allow_get_expansion" FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 */
3285 static int
Bram Moolenaare3226be2005-12-18 22:10:00 +00003286ins_compl_next(allow_get_expansion, count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 int allow_get_expansion;
Bram Moolenaare3226be2005-12-18 22:10:00 +00003288 int count; /* repeat completion this many times; should
3289 be at least 1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290{
3291 int num_matches = -1;
3292 int i;
Bram Moolenaare3226be2005-12-18 22:10:00 +00003293 int todo = count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294
3295 if (allow_get_expansion)
3296 {
3297 /* Delete old text to be replaced */
3298 ins_compl_delete();
3299 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003300 compl_pending = FALSE;
Bram Moolenaare3226be2005-12-18 22:10:00 +00003301
3302 /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
3303 * around. */
3304 while (--todo >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305 {
Bram Moolenaare3226be2005-12-18 22:10:00 +00003306 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307 {
Bram Moolenaare3226be2005-12-18 22:10:00 +00003308 compl_shown_match = compl_shown_match->cp_next;
3309 if (compl_shown_match->cp_next != NULL
3310 && compl_shown_match->cp_next == compl_first_match)
3311 break;
3312 }
3313 else if (compl_shows_dir == BACKWARD
3314 && compl_shown_match->cp_prev != NULL)
3315 {
3316 compl_shown_match = compl_shown_match->cp_prev;
3317 if (compl_shown_match == compl_first_match)
3318 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 }
3320 else
Bram Moolenaare3226be2005-12-18 22:10:00 +00003321 {
3322 compl_pending = TRUE;
3323 if (allow_get_expansion)
3324 {
3325 num_matches = ins_compl_get_exp(&compl_startpos,
3326 compl_direction);
3327 if (compl_pending)
3328 {
3329 if (compl_direction == compl_shows_dir)
3330 compl_shown_match = compl_curr_match;
3331 }
3332 }
3333 else
3334 return -1;
3335 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 }
3337
3338 /* Insert the text of the new completion */
3339 ins_compl_insert();
3340
3341 if (!allow_get_expansion)
3342 {
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003343 /* may undisplay the popup menu first */
3344 ins_compl_upd_pum();
3345
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 /* Display the current match. */
3347 update_screen(0);
3348
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003349 /* display the updated popup menu */
3350 ins_compl_show_pum();
3351
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 /* Delete old text to be replaced, since we're still searching and
3353 * don't want to match ourselves! */
3354 ins_compl_delete();
3355 }
3356
3357 /*
3358 * Show the file name for the match (if any)
3359 * Truncate the file name to avoid a wait for return.
3360 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003361 if (compl_shown_match->cp_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362 {
3363 STRCPY(IObuff, "match in file ");
Bram Moolenaar572cb562005-08-05 21:35:02 +00003364 i = (vim_strsize(compl_shown_match->cp_fname) + 16) - sc_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 if (i <= 0)
3366 i = 0;
3367 else
3368 STRCAT(IObuff, "<");
Bram Moolenaar572cb562005-08-05 21:35:02 +00003369 STRCAT(IObuff, compl_shown_match->cp_fname + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 msg(IObuff);
3371 redraw_cmdline = FALSE; /* don't overwrite! */
3372 }
3373
3374 return num_matches;
3375}
3376
3377/*
3378 * Call this while finding completions, to check whether the user has hit a key
3379 * that should change the currently displayed completion, or exit completion
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003380 * mode. Also, when compl_pending is TRUE, show a completion as soon as
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 * possible. -- webb
Bram Moolenaar572cb562005-08-05 21:35:02 +00003382 * "frequency" specifies out of how many calls we actually check.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 */
3384 void
Bram Moolenaar572cb562005-08-05 21:35:02 +00003385ins_compl_check_keys(frequency)
3386 int frequency;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387{
3388 static int count = 0;
3389
3390 int c;
3391
3392 /* Don't check when reading keys from a script. That would break the test
3393 * scripts */
3394 if (using_script())
3395 return;
3396
3397 /* Only do this at regular intervals */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003398 if (++count < frequency)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003399 return;
3400 count = 0;
3401
3402 ++no_mapping;
3403 c = vpeekc_any();
3404 --no_mapping;
3405 if (c != NUL)
3406 {
3407 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
3408 {
3409 c = safe_vgetc(); /* Eat the character */
Bram Moolenaare3226be2005-12-18 22:10:00 +00003410 compl_shows_dir = ins_compl_key2dir(c);
3411 (void)ins_compl_next(FALSE, ins_compl_key2count(c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 }
3413 else if (c != Ctrl_R)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003414 compl_interrupted = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003416 if (compl_pending && !got_int)
Bram Moolenaare3226be2005-12-18 22:10:00 +00003417 (void)ins_compl_next(FALSE, 1);
3418}
3419
3420/*
3421 * Decide the direction of Insert mode complete from the key typed.
3422 * Returns BACKWARD or FORWARD.
3423 */
3424 static int
3425ins_compl_key2dir(c)
3426 int c;
3427{
3428 if (c == Ctrl_P || c == Ctrl_L || (pum_visible()
3429 && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP)))
3430 return BACKWARD;
3431 return FORWARD;
3432}
3433
3434/*
3435 * Decide the number of completions to move forward.
3436 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
3437 */
3438 static int
3439ins_compl_key2count(c)
3440 int c;
3441{
3442 int h;
3443
3444 if (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
3445 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN))
3446 {
3447 h = pum_get_height();
3448 if (h > 3)
3449 h -= 2; /* keep some context */
3450 return h;
3451 }
3452 return 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003453}
3454
3455/*
3456 * Do Insert mode completion.
3457 * Called when character "c" was typed, which has a meaning for completion.
3458 * Returns OK if completion was done, FAIL if something failed (out of mem).
3459 */
3460 static int
3461ins_complete(c)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003462 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003464 char_u *line;
3465 int startcol = 0; /* column where searched text starts */
3466 colnr_T curs_col; /* cursor column */
3467 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468
Bram Moolenaare3226be2005-12-18 22:10:00 +00003469 compl_direction = ins_compl_key2dir(c);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003470 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 {
3472 /* First time we hit ^N or ^P (in a row, I mean) */
3473
3474 /* Turn off 'sm' so we don't show matches with ^X^L */
3475 save_sm = p_sm;
3476 p_sm = FALSE;
3477
3478 did_ai = FALSE;
3479#ifdef FEAT_SMARTINDENT
3480 did_si = FALSE;
3481 can_si = FALSE;
3482 can_si_back = FALSE;
3483#endif
3484 if (stop_arrow() == FAIL)
3485 return FAIL;
3486
3487 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003488 curs_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489
3490 /* if this same ctrl_x_mode has been interrupted use the text from
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003491 * "compl_startpos" to the cursor as a pattern to add a new word
3492 * instead of expand the one before the cursor, in word-wise if
3493 * "compl_startpos"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494 * is not in the same line as the cursor then fix it (the line has
3495 * been split because it was longer than 'tw'). if SOL is set then
3496 * skip the previous pattern, a word at the beginning of the line has
3497 * been inserted, we'll look for that -- Acevedo. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003498 if ((compl_cont_status & CONT_INTRPT) && compl_cont_mode == ctrl_x_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 {
3500 /*
3501 * it is a continued search
3502 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003503 compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504 if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
3505 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
3506 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003507 if (compl_startpos.lnum != curwin->w_cursor.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003509 /* line (probably) wrapped, set compl_startpos to the
3510 * first non_blank in the line, if it is not a wordchar
3511 * include it to get a better pattern, but then we don't
3512 * want the "\\<" prefix, check it bellow */
3513 compl_col = (colnr_T)(skipwhite(line) - line);
3514 compl_startpos.col = compl_col;
3515 compl_startpos.lnum = curwin->w_cursor.lnum;
3516 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 }
3518 else
3519 {
3520 /* S_IPOS was set when we inserted a word that was at the
3521 * beginning of the line, which means that we'll go to SOL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003522 * mode but first we need to redefine compl_startpos */
3523 if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003525 compl_cont_status |= CONT_SOL;
3526 compl_startpos.col = (colnr_T)(skipwhite(
3527 line + compl_length
3528 + compl_startpos.col) - line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003530 compl_col = compl_startpos.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003532 compl_length = curwin->w_cursor.col - (int)compl_col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003533 /* IObuff is used to add a "word from the next line" would we
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534 * have enough space? just being paranoic */
3535#define MIN_SPACE 75
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003536 if (compl_length > (IOSIZE - MIN_SPACE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003538 compl_cont_status &= ~CONT_SOL;
3539 compl_length = (IOSIZE - MIN_SPACE);
3540 compl_col = curwin->w_cursor.col - compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003542 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
3543 if (compl_length < 1)
3544 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545 }
3546 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003547 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003549 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003550 }
3551 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003552 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003554 if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003556 compl_cont_mode = ctrl_x_mode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557 if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003558 compl_cont_status = 0;
3559 compl_cont_status |= CONT_N_ADDS;
3560 compl_startpos = curwin->w_cursor;
3561 startcol = (int)curs_col;
3562 compl_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003563 }
3564
3565 /* Work out completion pattern and original text -- webb */
3566 if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
3567 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003568 if ((compl_cont_status & CONT_SOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
3570 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003571 if (!(compl_cont_status & CONT_ADDING))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003573 while (--startcol >= 0 && vim_isIDc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003575 compl_col += ++startcol;
3576 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 }
3578 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003579 compl_pattern = str_foldcase(line + compl_col,
3580 compl_length, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003582 compl_pattern = vim_strnsave(line + compl_col,
3583 compl_length);
3584 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585 return FAIL;
3586 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003587 else if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 {
3589 char_u *prefix = (char_u *)"\\<";
3590
3591 /* we need 3 extra chars, 1 for the NUL and
3592 * 2 >= strlen(prefix) -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003593 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
3594 compl_length) + 3);
3595 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003597 if (!vim_iswordp(line + compl_col)
3598 || (compl_col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599 && (
3600#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003601 vim_iswordp(mb_prevptr(line, line + compl_col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003603 vim_iswordc(line[compl_col - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604#endif
3605 )))
3606 prefix = (char_u *)"";
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003607 STRCPY((char *)compl_pattern, prefix);
3608 (void)quote_meta(compl_pattern + STRLEN(prefix),
3609 line + compl_col, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003611 else if (--startcol < 0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003613 !vim_iswordp(mb_prevptr(line, line + startcol + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003615 !vim_iswordc(line[startcol])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616#endif
3617 )
3618 {
3619 /* Match any word of at least two chars */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003620 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
3621 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003623 compl_col += curs_col;
3624 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625 }
3626 else
3627 {
3628#ifdef FEAT_MBYTE
3629 /* Search the point of change class of multibyte character
3630 * or not a word single byte character backward. */
3631 if (has_mbyte)
3632 {
3633 int base_class;
3634 int head_off;
3635
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003636 startcol -= (*mb_head_off)(line, line + startcol);
3637 base_class = mb_get_class(line + startcol);
3638 while (--startcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003640 head_off = (*mb_head_off)(line, line + startcol);
3641 if (base_class != mb_get_class(line + startcol
3642 - head_off))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003644 startcol -= head_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645 }
3646 }
3647 else
3648#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003649 while (--startcol >= 0 && vim_iswordc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003651 compl_col += ++startcol;
3652 compl_length = (int)curs_col - startcol;
3653 if (compl_length == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 {
3655 /* Only match word with at least two chars -- webb
3656 * there's no need to call quote_meta,
3657 * alloc(7) is enough -- Acevedo
3658 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003659 compl_pattern = alloc(7);
3660 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003662 STRCPY((char *)compl_pattern, "\\<");
3663 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
3664 STRCAT((char *)compl_pattern, "\\k");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 }
3666 else
3667 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003668 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
3669 compl_length) + 3);
3670 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003672 STRCPY((char *)compl_pattern, "\\<");
3673 (void)quote_meta(compl_pattern + 2, line + compl_col,
3674 compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675 }
3676 }
3677 }
3678 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3679 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003680 compl_col = skipwhite(line) - line;
3681 compl_length = (int)curs_col - (int)compl_col;
3682 if (compl_length < 0) /* cursor in indent: empty pattern */
3683 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003685 compl_pattern = str_foldcase(line + compl_col, compl_length,
3686 NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003688 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3689 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 return FAIL;
3691 }
3692 else if (ctrl_x_mode == CTRL_X_FILES)
3693 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003694 while (--startcol >= 0 && vim_isfilec(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003696 compl_col += ++startcol;
3697 compl_length = (int)curs_col - startcol;
3698 compl_pattern = addstar(line + compl_col, compl_length,
3699 EXPAND_FILES);
3700 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 return FAIL;
3702 }
3703 else if (ctrl_x_mode == CTRL_X_CMDLINE)
3704 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003705 compl_pattern = vim_strnsave(line, curs_col);
3706 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003708 set_cmd_context(&compl_xp, compl_pattern,
3709 (int)STRLEN(compl_pattern), curs_col);
3710 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
3711 || compl_xp.xp_context == EXPAND_NOTHING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003713 startcol = (int)(compl_xp.xp_pattern - compl_pattern);
3714 compl_col = startcol;
3715 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 }
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003717 else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003718 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00003719#ifdef FEAT_COMPL_FUNC
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003720 /*
Bram Moolenaare344bea2005-09-01 20:46:49 +00003721 * Call user defined function 'completefunc' with "a:findstart"
3722 * set to 1 to obtain the length of text to use for completion.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003723 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00003724 char_u *args[2];
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003725 int col;
Bram Moolenaare344bea2005-09-01 20:46:49 +00003726 char_u *funcname;
3727 pos_T pos;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003728
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003729 /* Call 'completefunc' or 'omnifunc' and get pattern length as a
Bram Moolenaare344bea2005-09-01 20:46:49 +00003730 * string */
3731 funcname = ctrl_x_mode == CTRL_X_FUNCTION
3732 ? curbuf->b_p_cfu : curbuf->b_p_ofu;
3733 if (*funcname == NUL)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003734 {
3735 EMSG2(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
3736 ? "completefunc" : "omnifunc");
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003737 return FAIL;
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003738 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003739
3740 args[0] = (char_u *)"1";
Bram Moolenaare344bea2005-09-01 20:46:49 +00003741 args[1] = NULL;
3742 pos = curwin->w_cursor;
3743 col = call_func_retnr(funcname, 2, args, FALSE);
3744 curwin->w_cursor = pos; /* restore the cursor position */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003745
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003746 if (col < 0)
Bram Moolenaarf75a9632005-09-13 21:20:47 +00003747 col = curs_col;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003748 compl_col = col;
3749 if ((colnr_T)compl_col > curs_col)
3750 compl_col = curs_col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003751
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003752 /* Setup variables for completion. Need to obtain "line" again,
3753 * it may have become invalid. */
3754 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003755 compl_length = curs_col - compl_col;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003756 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3757 if (compl_pattern == NULL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003758#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003759 return FAIL;
3760 }
Bram Moolenaar488c6512005-08-11 20:09:58 +00003761 else if (ctrl_x_mode == CTRL_X_SPELL)
3762 {
3763#ifdef FEAT_SYN_HL
Bram Moolenaar6e7c7f32005-08-24 22:16:11 +00003764 if (spell_bad_len > 0)
3765 compl_col = curs_col - spell_bad_len;
3766 else
3767 compl_col = spell_word_start(startcol);
3768 if (compl_col >= (colnr_T)startcol)
Bram Moolenaar488c6512005-08-11 20:09:58 +00003769 return FAIL;
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00003770 spell_expand_check_cap(compl_col);
Bram Moolenaar488c6512005-08-11 20:09:58 +00003771 compl_length = (int)curs_col - compl_col;
3772 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3773 if (compl_pattern == NULL)
3774#endif
3775 return FAIL;
3776 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003777 else
3778 {
3779 EMSG2(_(e_intern2), "ins_complete()");
3780 return FAIL;
3781 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003783 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784 {
3785 edit_submode_pre = (char_u *)_(" Adding");
3786 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3787 {
3788 /* Insert a new line, keep indentation but ignore 'comments' */
3789#ifdef FEAT_COMMENTS
3790 char_u *old = curbuf->b_p_com;
3791
3792 curbuf->b_p_com = (char_u *)"";
3793#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003794 compl_startpos.lnum = curwin->w_cursor.lnum;
3795 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 ins_eol('\r');
3797#ifdef FEAT_COMMENTS
3798 curbuf->b_p_com = old;
3799#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003800 compl_length = 0;
3801 compl_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 }
3803 }
3804 else
3805 {
3806 edit_submode_pre = NULL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003807 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 }
3809
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003810 if (compl_cont_status & CONT_LOCAL)
3811 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 else
3813 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
3814
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 /* Always add completion for the original text. Note that
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003816 * "compl_orig_text" itself (not a copy) is added, it will be freed
3817 * when the list of matches is freed. */
3818 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
3819 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
3820 -1, NULL, 0, ORIGINAL_TEXT) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003822 vim_free(compl_pattern);
3823 compl_pattern = NULL;
3824 vim_free(compl_orig_text);
3825 compl_orig_text = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 return FAIL;
3827 }
3828
3829 /* showmode might reset the internal line pointers, so it must
3830 * be called before line = ml_get(), or when this address is no
3831 * longer needed. -- Acevedo.
3832 */
3833 edit_submode_extra = (char_u *)_("-- Searching...");
3834 edit_submode_highl = HLF_COUNT;
3835 showmode();
3836 edit_submode_extra = NULL;
3837 out_flush();
3838 }
3839
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003840 compl_shown_match = compl_curr_match;
3841 compl_shows_dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842
3843 /*
3844 * Find next match.
3845 */
Bram Moolenaare3226be2005-12-18 22:10:00 +00003846 n = ins_compl_next(TRUE, ins_compl_key2count(c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003848 /* may undisplay the popup menu */
3849 ins_compl_upd_pum();
3850
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003851 if (n > 1) /* all matches have been found */
3852 compl_matches = n;
3853 compl_curr_match = compl_shown_match;
3854 compl_direction = compl_shows_dir;
3855 compl_interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856
3857 /* eat the ESC to avoid leaving insert mode */
3858 if (got_int && !global_busy)
3859 {
3860 (void)vgetc();
3861 got_int = FALSE;
3862 }
3863
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003864 /* we found no match if the list has only the "compl_orig_text"-entry */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003865 if (compl_first_match == compl_first_match->cp_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003867 edit_submode_extra = (compl_cont_status & CONT_ADDING)
3868 && compl_length > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
3870 edit_submode_highl = HLF_E;
3871 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
3872 * because we couldn't expand anything at first place, but if we used
3873 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
3874 * (such as M in M'exico) if not tried already. -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003875 if ( compl_length > 1
3876 || (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 || (ctrl_x_mode != 0
3878 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
3879 && ctrl_x_mode != CTRL_X_PATH_DEFINES))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003880 compl_cont_status &= ~CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 }
3882
Bram Moolenaar572cb562005-08-05 21:35:02 +00003883 if (compl_curr_match->cp_flags & CONT_S_IPOS)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003884 compl_cont_status |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003886 compl_cont_status &= ~CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887
3888 if (edit_submode_extra == NULL)
3889 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003890 if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 {
3892 edit_submode_extra = (char_u *)_("Back at original");
3893 edit_submode_highl = HLF_W;
3894 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003895 else if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 {
3897 edit_submode_extra = (char_u *)_("Word from other line");
3898 edit_submode_highl = HLF_COUNT;
3899 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00003900 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 {
3902 edit_submode_extra = (char_u *)_("The only match");
3903 edit_submode_highl = HLF_COUNT;
3904 }
3905 else
3906 {
3907 /* Update completion sequence number when needed. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003908 if (compl_curr_match->cp_number == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003910 int number = 0;
3911 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003913 if (compl_direction == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003914 {
3915 /* search backwards for the first valid (!= -1) number.
3916 * This should normally succeed already at the first loop
3917 * cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003918 for (match = compl_curr_match->cp_prev; match != NULL
3919 && match != compl_first_match;
3920 match = match->cp_prev)
3921 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003923 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924 break;
3925 }
3926 if (match != NULL)
3927 /* go up and assign all numbers which are not assigned
3928 * yet */
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003929 for (match = match->cp_next;
3930 match != NULL && match->cp_number == -1;
Bram Moolenaar572cb562005-08-05 21:35:02 +00003931 match = match->cp_next)
3932 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 }
3934 else /* BACKWARD */
3935 {
3936 /* search forwards (upwards) for the first valid (!= -1)
3937 * number. This should normally succeed already at the
3938 * first loop cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003939 for (match = compl_curr_match->cp_next; match != NULL
3940 && match != compl_first_match;
3941 match = match->cp_next)
3942 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003944 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 break;
3946 }
3947 if (match != NULL)
3948 /* go down and assign all numbers which are not
3949 * assigned yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003950 for (match = match->cp_prev; match
3951 && match->cp_number == -1;
3952 match = match->cp_prev)
3953 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 }
3955 }
3956
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003957 /* The match should always have a sequence number now, this is
3958 * just a safety check. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003959 if (compl_curr_match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 {
3961 /* Space for 10 text chars. + 2x10-digit no.s */
3962 static char_u match_ref[31];
3963
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003964 if (compl_matches > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 sprintf((char *)IObuff, _("match %d of %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00003966 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003967 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003968 sprintf((char *)IObuff, _("match %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00003969 compl_curr_match->cp_number);
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003970 vim_strncpy(match_ref, IObuff, 30);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971 edit_submode_extra = match_ref;
3972 edit_submode_highl = HLF_R;
3973 if (dollar_vcol)
3974 curs_columns(FALSE);
3975 }
3976 }
3977 }
3978
3979 /* Show a message about what (completion) mode we're in. */
3980 showmode();
3981 if (edit_submode_extra != NULL)
3982 {
3983 if (!p_smd)
3984 msg_attr(edit_submode_extra,
3985 edit_submode_highl < HLF_COUNT
3986 ? hl_attr(edit_submode_highl) : 0);
3987 }
3988 else
3989 msg_clr_cmdline(); /* necessary for "noshowmode" */
3990
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003991 ins_compl_show_pum();
3992
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 return OK;
3994}
3995
3996/*
3997 * Looks in the first "len" chars. of "src" for search-metachars.
3998 * If dest is not NULL the chars. are copied there quoting (with
3999 * a backslash) the metachars, and dest would be NUL terminated.
4000 * Returns the length (needed) of dest
4001 */
4002 static int
4003quote_meta(dest, src, len)
4004 char_u *dest;
4005 char_u *src;
4006 int len;
4007{
4008 int m;
4009
4010 for (m = len; --len >= 0; src++)
4011 {
4012 switch (*src)
4013 {
4014 case '.':
4015 case '*':
4016 case '[':
4017 if (ctrl_x_mode == CTRL_X_DICTIONARY
4018 || ctrl_x_mode == CTRL_X_THESAURUS)
4019 break;
4020 case '~':
4021 if (!p_magic) /* quote these only if magic is set */
4022 break;
4023 case '\\':
4024 if (ctrl_x_mode == CTRL_X_DICTIONARY
4025 || ctrl_x_mode == CTRL_X_THESAURUS)
4026 break;
4027 case '^': /* currently it's not needed. */
4028 case '$':
4029 m++;
4030 if (dest != NULL)
4031 *dest++ = '\\';
4032 break;
4033 }
4034 if (dest != NULL)
4035 *dest++ = *src;
Bram Moolenaar572cb562005-08-05 21:35:02 +00004036# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037 /* Copy remaining bytes of a multibyte character. */
4038 if (has_mbyte)
4039 {
4040 int i, mb_len;
4041
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004042 mb_len = (*mb_ptr2len)(src) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 if (mb_len > 0 && len >= mb_len)
4044 for (i = 0; i < mb_len; ++i)
4045 {
4046 --len;
4047 ++src;
4048 if (dest != NULL)
4049 *dest++ = *src;
4050 }
4051 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00004052# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053 }
4054 if (dest != NULL)
4055 *dest = NUL;
4056
4057 return m;
4058}
4059#endif /* FEAT_INS_EXPAND */
4060
4061/*
4062 * Next character is interpreted literally.
4063 * A one, two or three digit decimal number is interpreted as its byte value.
4064 * If one or two digits are entered, the next character is given to vungetc().
4065 * For Unicode a character > 255 may be returned.
4066 */
4067 int
4068get_literal()
4069{
4070 int cc;
4071 int nc;
4072 int i;
4073 int hex = FALSE;
4074 int octal = FALSE;
4075#ifdef FEAT_MBYTE
4076 int unicode = 0;
4077#endif
4078
4079 if (got_int)
4080 return Ctrl_C;
4081
4082#ifdef FEAT_GUI
4083 /*
4084 * In GUI there is no point inserting the internal code for a special key.
4085 * It is more useful to insert the string "<KEY>" instead. This would
4086 * probably be useful in a text window too, but it would not be
4087 * vi-compatible (maybe there should be an option for it?) -- webb
4088 */
4089 if (gui.in_use)
4090 ++allow_keys;
4091#endif
4092#ifdef USE_ON_FLY_SCROLL
4093 dont_scroll = TRUE; /* disallow scrolling here */
4094#endif
4095 ++no_mapping; /* don't map the next key hits */
4096 cc = 0;
4097 i = 0;
4098 for (;;)
4099 {
4100 do
4101 nc = safe_vgetc();
4102 while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
4103 || nc == K_HOR_SCROLLBAR);
4104#ifdef FEAT_CMDL_INFO
4105 if (!(State & CMDLINE)
4106# ifdef FEAT_MBYTE
4107 && MB_BYTE2LEN_CHECK(nc) == 1
4108# endif
4109 )
4110 add_to_showcmd(nc);
4111#endif
4112 if (nc == 'x' || nc == 'X')
4113 hex = TRUE;
4114 else if (nc == 'o' || nc == 'O')
4115 octal = TRUE;
4116#ifdef FEAT_MBYTE
4117 else if (nc == 'u' || nc == 'U')
4118 unicode = nc;
4119#endif
4120 else
4121 {
4122 if (hex
4123#ifdef FEAT_MBYTE
4124 || unicode != 0
4125#endif
4126 )
4127 {
4128 if (!vim_isxdigit(nc))
4129 break;
4130 cc = cc * 16 + hex2nr(nc);
4131 }
4132 else if (octal)
4133 {
4134 if (nc < '0' || nc > '7')
4135 break;
4136 cc = cc * 8 + nc - '0';
4137 }
4138 else
4139 {
4140 if (!VIM_ISDIGIT(nc))
4141 break;
4142 cc = cc * 10 + nc - '0';
4143 }
4144
4145 ++i;
4146 }
4147
4148 if (cc > 255
4149#ifdef FEAT_MBYTE
4150 && unicode == 0
4151#endif
4152 )
4153 cc = 255; /* limit range to 0-255 */
4154 nc = 0;
4155
4156 if (hex) /* hex: up to two chars */
4157 {
4158 if (i >= 2)
4159 break;
4160 }
4161#ifdef FEAT_MBYTE
4162 else if (unicode) /* Unicode: up to four or eight chars */
4163 {
4164 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
4165 break;
4166 }
4167#endif
4168 else if (i >= 3) /* decimal or octal: up to three chars */
4169 break;
4170 }
4171 if (i == 0) /* no number entered */
4172 {
4173 if (nc == K_ZERO) /* NUL is stored as NL */
4174 {
4175 cc = '\n';
4176 nc = 0;
4177 }
4178 else
4179 {
4180 cc = nc;
4181 nc = 0;
4182 }
4183 }
4184
4185 if (cc == 0) /* NUL is stored as NL */
4186 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00004187#ifdef FEAT_MBYTE
4188 if (enc_dbcs && (cc & 0xff) == 0)
4189 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
4190 second byte will cause trouble! */
4191#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192
4193 --no_mapping;
4194#ifdef FEAT_GUI
4195 if (gui.in_use)
4196 --allow_keys;
4197#endif
4198 if (nc)
4199 vungetc(nc);
4200 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
4201 return cc;
4202}
4203
4204/*
4205 * Insert character, taking care of special keys and mod_mask
4206 */
4207 static void
4208insert_special(c, allow_modmask, ctrlv)
4209 int c;
4210 int allow_modmask;
4211 int ctrlv; /* c was typed after CTRL-V */
4212{
4213 char_u *p;
4214 int len;
4215
4216 /*
4217 * Special function key, translate into "<Key>". Up to the last '>' is
4218 * inserted with ins_str(), so as not to replace characters in replace
4219 * mode.
4220 * Only use mod_mask for special keys, to avoid things like <S-Space>,
4221 * unless 'allow_modmask' is TRUE.
4222 */
4223#ifdef MACOS
4224 /* Command-key never produces a normal key */
4225 if (mod_mask & MOD_MASK_CMD)
4226 allow_modmask = TRUE;
4227#endif
4228 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
4229 {
4230 p = get_special_key_name(c, mod_mask);
4231 len = (int)STRLEN(p);
4232 c = p[len - 1];
4233 if (len > 2)
4234 {
4235 if (stop_arrow() == FAIL)
4236 return;
4237 p[len - 1] = NUL;
4238 ins_str(p);
4239 AppendToRedobuffLit(p);
4240 ctrlv = FALSE;
4241 }
4242 }
4243 if (stop_arrow() == OK)
4244 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
4245}
4246
4247/*
4248 * Special characters in this context are those that need processing other
4249 * than the simple insertion that can be performed here. This includes ESC
4250 * which terminates the insert, and CR/NL which need special processing to
4251 * open up a new line. This routine tries to optimize insertions performed by
4252 * the "redo", "undo" or "put" commands, so it needs to know when it should
4253 * stop and defer processing to the "normal" mechanism.
4254 * '0' and '^' are special, because they can be followed by CTRL-D.
4255 */
4256#ifdef EBCDIC
4257# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
4258#else
4259# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
4260#endif
4261
4262#ifdef FEAT_MBYTE
4263# define WHITECHAR(cc) (vim_iswhite(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
4264#else
4265# define WHITECHAR(cc) vim_iswhite(cc)
4266#endif
4267
4268 void
4269insertchar(c, flags, second_indent)
4270 int c; /* character to insert or NUL */
4271 int flags; /* INSCHAR_FORMAT, etc. */
4272 int second_indent; /* indent for second line if >= 0 */
4273{
4274 int haveto_redraw = FALSE;
4275 int textwidth;
4276#ifdef FEAT_COMMENTS
4277 colnr_T leader_len;
4278 char_u *p;
4279 int no_leader = FALSE;
4280 int do_comments = (flags & INSCHAR_DO_COM);
4281#endif
4282 int fo_white_par;
4283 int first_line = TRUE;
4284 int fo_ins_blank;
4285#ifdef FEAT_MBYTE
4286 int fo_multibyte;
4287#endif
4288 int save_char = NUL;
4289 int cc;
4290
4291 textwidth = comp_textwidth(flags & INSCHAR_FORMAT);
4292 fo_ins_blank = has_format_option(FO_INS_BLANK);
4293#ifdef FEAT_MBYTE
4294 fo_multibyte = has_format_option(FO_MBYTE_BREAK);
4295#endif
4296 fo_white_par = has_format_option(FO_WHITE_PAR);
4297
4298 /*
4299 * Try to break the line in two or more pieces when:
4300 * - Always do this if we have been called to do formatting only.
4301 * - Always do this when 'formatoptions' has the 'a' flag and the line
4302 * ends in white space.
4303 * - Otherwise:
4304 * - Don't do this if inserting a blank
4305 * - Don't do this if an existing character is being replaced, unless
4306 * we're in VREPLACE mode.
4307 * - Do this if the cursor is not on the line where insert started
4308 * or - 'formatoptions' doesn't have 'l' or the line was not too long
4309 * before the insert.
4310 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
4311 * before 'textwidth'
4312 */
4313 if (textwidth
4314 && ((flags & INSCHAR_FORMAT)
4315 || (!vim_iswhite(c)
4316 && !((State & REPLACE_FLAG)
4317#ifdef FEAT_VREPLACE
4318 && !(State & VREPLACE_FLAG)
4319#endif
4320 && *ml_get_cursor() != NUL)
4321 && (curwin->w_cursor.lnum != Insstart.lnum
4322 || ((!has_format_option(FO_INS_LONG)
4323 || Insstart_textlen <= (colnr_T)textwidth)
4324 && (!fo_ins_blank
4325 || Insstart_blank_vcol <= (colnr_T)textwidth
4326 ))))))
4327 {
4328 /*
4329 * When 'ai' is off we don't want a space under the cursor to be
4330 * deleted. Replace it with an 'x' temporarily.
4331 */
4332 if (!curbuf->b_p_ai)
4333 {
4334 cc = gchar_cursor();
4335 if (vim_iswhite(cc))
4336 {
4337 save_char = cc;
4338 pchar_cursor('x');
4339 }
4340 }
4341
4342 /*
4343 * Repeat breaking lines, until the current line is not too long.
4344 */
4345 while (!got_int)
4346 {
4347 int startcol; /* Cursor column at entry */
4348 int wantcol; /* column at textwidth border */
4349 int foundcol; /* column for start of spaces */
4350 int end_foundcol = 0; /* column for start of word */
4351 colnr_T len;
4352 colnr_T virtcol;
4353#ifdef FEAT_VREPLACE
4354 int orig_col = 0;
4355 char_u *saved_text = NULL;
4356#endif
4357 colnr_T col;
4358
4359 virtcol = get_nolist_virtcol();
4360 if (virtcol < (colnr_T)textwidth)
4361 break;
4362
4363#ifdef FEAT_COMMENTS
4364 if (no_leader)
4365 do_comments = FALSE;
4366 else if (!(flags & INSCHAR_FORMAT)
4367 && has_format_option(FO_WRAP_COMS))
4368 do_comments = TRUE;
4369
4370 /* Don't break until after the comment leader */
4371 if (do_comments)
4372 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE);
4373 else
4374 leader_len = 0;
4375
4376 /* If the line doesn't start with a comment leader, then don't
4377 * start one in a following broken line. Avoids that a %word
4378 * moved to the start of the next line causes all following lines
4379 * to start with %. */
4380 if (leader_len == 0)
4381 no_leader = TRUE;
4382#endif
4383 if (!(flags & INSCHAR_FORMAT)
4384#ifdef FEAT_COMMENTS
4385 && leader_len == 0
4386#endif
4387 && !has_format_option(FO_WRAP))
4388
4389 {
4390 textwidth = 0;
4391 break;
4392 }
4393 if ((startcol = curwin->w_cursor.col) == 0)
4394 break;
4395
4396 /* find column of textwidth border */
4397 coladvance((colnr_T)textwidth);
4398 wantcol = curwin->w_cursor.col;
4399
4400 curwin->w_cursor.col = startcol - 1;
4401#ifdef FEAT_MBYTE
4402 /* Correct cursor for multi-byte character. */
4403 if (has_mbyte)
4404 mb_adjust_cursor();
4405#endif
4406 foundcol = 0;
4407
4408 /*
4409 * Find position to break at.
4410 * Stop at first entered white when 'formatoptions' has 'v'
4411 */
4412 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
4413 || curwin->w_cursor.lnum != Insstart.lnum
4414 || curwin->w_cursor.col >= Insstart.col)
4415 {
4416 cc = gchar_cursor();
4417 if (WHITECHAR(cc))
4418 {
4419 /* remember position of blank just before text */
4420 end_foundcol = curwin->w_cursor.col;
4421
4422 /* find start of sequence of blanks */
4423 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
4424 {
4425 dec_cursor();
4426 cc = gchar_cursor();
4427 }
4428 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
4429 break; /* only spaces in front of text */
4430#ifdef FEAT_COMMENTS
4431 /* Don't break until after the comment leader */
4432 if (curwin->w_cursor.col < leader_len)
4433 break;
4434#endif
4435 if (has_format_option(FO_ONE_LETTER))
4436 {
4437 /* do not break after one-letter words */
4438 if (curwin->w_cursor.col == 0)
4439 break; /* one-letter word at begin */
4440
4441 col = curwin->w_cursor.col;
4442 dec_cursor();
4443 cc = gchar_cursor();
4444
4445 if (WHITECHAR(cc))
4446 continue; /* one-letter, continue */
4447 curwin->w_cursor.col = col;
4448 }
4449#ifdef FEAT_MBYTE
4450 if (has_mbyte)
4451 foundcol = curwin->w_cursor.col
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004452 + (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453 else
4454#endif
4455 foundcol = curwin->w_cursor.col + 1;
4456 if (curwin->w_cursor.col < (colnr_T)wantcol)
4457 break;
4458 }
4459#ifdef FEAT_MBYTE
4460 else if (cc >= 0x100 && fo_multibyte
4461 && curwin->w_cursor.col <= (colnr_T)wantcol)
4462 {
4463 /* Break after or before a multi-byte character. */
4464 foundcol = curwin->w_cursor.col;
4465 if (curwin->w_cursor.col < (colnr_T)wantcol)
4466 foundcol += (*mb_char2len)(cc);
4467 end_foundcol = foundcol;
4468 break;
4469 }
4470#endif
4471 if (curwin->w_cursor.col == 0)
4472 break;
4473 dec_cursor();
4474 }
4475
4476 if (foundcol == 0) /* no spaces, cannot break line */
4477 {
4478 curwin->w_cursor.col = startcol;
4479 break;
4480 }
4481
4482 /* Going to break the line, remove any "$" now. */
4483 undisplay_dollar();
4484
4485 /*
4486 * Offset between cursor position and line break is used by replace
4487 * stack functions. VREPLACE does not use this, and backspaces
4488 * over the text instead.
4489 */
4490#ifdef FEAT_VREPLACE
4491 if (State & VREPLACE_FLAG)
4492 orig_col = startcol; /* Will start backspacing from here */
4493 else
4494#endif
4495 replace_offset = startcol - end_foundcol - 1;
4496
4497 /*
4498 * adjust startcol for spaces that will be deleted and
4499 * characters that will remain on top line
4500 */
4501 curwin->w_cursor.col = foundcol;
4502 while (cc = gchar_cursor(), WHITECHAR(cc))
4503 inc_cursor();
4504 startcol -= curwin->w_cursor.col;
4505 if (startcol < 0)
4506 startcol = 0;
4507
4508#ifdef FEAT_VREPLACE
4509 if (State & VREPLACE_FLAG)
4510 {
4511 /*
4512 * In VREPLACE mode, we will backspace over the text to be
4513 * wrapped, so save a copy now to put on the next line.
4514 */
4515 saved_text = vim_strsave(ml_get_cursor());
4516 curwin->w_cursor.col = orig_col;
4517 if (saved_text == NULL)
4518 break; /* Can't do it, out of memory */
4519 saved_text[startcol] = NUL;
4520
4521 /* Backspace over characters that will move to the next line */
4522 if (!fo_white_par)
4523 backspace_until_column(foundcol);
4524 }
4525 else
4526#endif
4527 {
4528 /* put cursor after pos. to break line */
4529 if (!fo_white_par)
4530 curwin->w_cursor.col = foundcol;
4531 }
4532
4533 /*
4534 * Split the line just before the margin.
4535 * Only insert/delete lines, but don't really redraw the window.
4536 */
4537 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
4538 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
4539#ifdef FEAT_COMMENTS
4540 + (do_comments ? OPENLINE_DO_COM : 0)
4541#endif
4542 , old_indent);
4543 old_indent = 0;
4544
4545 replace_offset = 0;
4546 if (first_line)
4547 {
4548 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
4549 second_indent = get_number_indent(curwin->w_cursor.lnum -1);
4550 if (second_indent >= 0)
4551 {
4552#ifdef FEAT_VREPLACE
4553 if (State & VREPLACE_FLAG)
4554 change_indent(INDENT_SET, second_indent, FALSE, NUL);
4555 else
4556#endif
4557 (void)set_indent(second_indent, SIN_CHANGED);
4558 }
4559 first_line = FALSE;
4560 }
4561
4562#ifdef FEAT_VREPLACE
4563 if (State & VREPLACE_FLAG)
4564 {
4565 /*
4566 * In VREPLACE mode we have backspaced over the text to be
4567 * moved, now we re-insert it into the new line.
4568 */
4569 ins_bytes(saved_text);
4570 vim_free(saved_text);
4571 }
4572 else
4573#endif
4574 {
4575 /*
4576 * Check if cursor is not past the NUL off the line, cindent
4577 * may have added or removed indent.
4578 */
4579 curwin->w_cursor.col += startcol;
4580 len = (colnr_T)STRLEN(ml_get_curline());
4581 if (curwin->w_cursor.col > len)
4582 curwin->w_cursor.col = len;
4583 }
4584
4585 haveto_redraw = TRUE;
4586#ifdef FEAT_CINDENT
4587 can_cindent = TRUE;
4588#endif
4589 /* moved the cursor, don't autoindent or cindent now */
4590 did_ai = FALSE;
4591#ifdef FEAT_SMARTINDENT
4592 did_si = FALSE;
4593 can_si = FALSE;
4594 can_si_back = FALSE;
4595#endif
4596 line_breakcheck();
4597 }
4598
4599 if (save_char) /* put back space after cursor */
4600 pchar_cursor(save_char);
4601
4602 if (c == NUL) /* formatting only */
4603 return;
4604 if (haveto_redraw)
4605 {
4606 update_topline();
4607 redraw_curbuf_later(VALID);
4608 }
4609 }
4610 if (c == NUL) /* only formatting was wanted */
4611 return;
4612
4613#ifdef FEAT_COMMENTS
4614 /* Check whether this character should end a comment. */
4615 if (did_ai && (int)c == end_comment_pending)
4616 {
4617 char_u *line;
4618 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
4619 int middle_len, end_len;
4620 int i;
4621
4622 /*
4623 * Need to remove existing (middle) comment leader and insert end
4624 * comment leader. First, check what comment leader we can find.
4625 */
4626 i = get_leader_len(line = ml_get_curline(), &p, FALSE);
4627 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
4628 {
4629 /* Skip middle-comment string */
4630 while (*p && p[-1] != ':') /* find end of middle flags */
4631 ++p;
4632 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
4633 /* Don't count trailing white space for middle_len */
4634 while (middle_len > 0 && vim_iswhite(lead_end[middle_len - 1]))
4635 --middle_len;
4636
4637 /* Find the end-comment string */
4638 while (*p && p[-1] != ':') /* find end of end flags */
4639 ++p;
4640 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
4641
4642 /* Skip white space before the cursor */
4643 i = curwin->w_cursor.col;
4644 while (--i >= 0 && vim_iswhite(line[i]))
4645 ;
4646 i++;
4647
4648 /* Skip to before the middle leader */
4649 i -= middle_len;
4650
4651 /* Check some expected things before we go on */
4652 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
4653 {
4654 /* Backspace over all the stuff we want to replace */
4655 backspace_until_column(i);
4656
4657 /*
4658 * Insert the end-comment string, except for the last
4659 * character, which will get inserted as normal later.
4660 */
4661 ins_bytes_len(lead_end, end_len - 1);
4662 }
4663 }
4664 }
4665 end_comment_pending = NUL;
4666#endif
4667
4668 did_ai = FALSE;
4669#ifdef FEAT_SMARTINDENT
4670 did_si = FALSE;
4671 can_si = FALSE;
4672 can_si_back = FALSE;
4673#endif
4674
4675 /*
4676 * If there's any pending input, grab up to INPUT_BUFLEN at once.
4677 * This speeds up normal text input considerably.
4678 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
4679 * need to re-indent at a ':', or any other character (but not what
4680 * 'paste' is set)..
4681 */
4682#ifdef USE_ON_FLY_SCROLL
4683 dont_scroll = FALSE; /* allow scrolling here */
4684#endif
4685
4686 if ( !ISSPECIAL(c)
4687#ifdef FEAT_MBYTE
4688 && (!has_mbyte || (*mb_char2len)(c) == 1)
4689#endif
4690 && vpeekc() != NUL
4691 && !(State & REPLACE_FLAG)
4692#ifdef FEAT_CINDENT
4693 && !cindent_on()
4694#endif
4695#ifdef FEAT_RIGHTLEFT
4696 && !p_ri
4697#endif
4698 )
4699 {
4700#define INPUT_BUFLEN 100
4701 char_u buf[INPUT_BUFLEN + 1];
4702 int i;
4703 colnr_T virtcol = 0;
4704
4705 buf[0] = c;
4706 i = 1;
4707 if (textwidth)
4708 virtcol = get_nolist_virtcol();
4709 /*
4710 * Stop the string when:
4711 * - no more chars available
4712 * - finding a special character (command key)
4713 * - buffer is full
4714 * - running into the 'textwidth' boundary
4715 * - need to check for abbreviation: A non-word char after a word-char
4716 */
4717 while ( (c = vpeekc()) != NUL
4718 && !ISSPECIAL(c)
4719#ifdef FEAT_MBYTE
4720 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
4721#endif
4722 && i < INPUT_BUFLEN
4723 && (textwidth == 0
4724 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
4725 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
4726 {
4727#ifdef FEAT_RIGHTLEFT
4728 c = vgetc();
4729 if (p_hkmap && KeyTyped)
4730 c = hkmap(c); /* Hebrew mode mapping */
4731# ifdef FEAT_FKMAP
4732 if (p_fkmap && KeyTyped)
4733 c = fkmap(c); /* Farsi mode mapping */
4734# endif
4735 buf[i++] = c;
4736#else
4737 buf[i++] = vgetc();
4738#endif
4739 }
4740
4741#ifdef FEAT_DIGRAPHS
4742 do_digraph(-1); /* clear digraphs */
4743 do_digraph(buf[i-1]); /* may be the start of a digraph */
4744#endif
4745 buf[i] = NUL;
4746 ins_str(buf);
4747 if (flags & INSCHAR_CTRLV)
4748 {
4749 redo_literal(*buf);
4750 i = 1;
4751 }
4752 else
4753 i = 0;
4754 if (buf[i] != NUL)
4755 AppendToRedobuffLit(buf + i);
4756 }
4757 else
4758 {
4759#ifdef FEAT_MBYTE
4760 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
4761 {
4762 char_u buf[MB_MAXBYTES + 1];
4763
4764 (*mb_char2bytes)(c, buf);
4765 buf[cc] = NUL;
4766 ins_char_bytes(buf, cc);
4767 AppendCharToRedobuff(c);
4768 }
4769 else
4770#endif
4771 {
4772 ins_char(c);
4773 if (flags & INSCHAR_CTRLV)
4774 redo_literal(c);
4775 else
4776 AppendCharToRedobuff(c);
4777 }
4778 }
4779}
4780
4781/*
4782 * Called after inserting or deleting text: When 'formatoptions' includes the
4783 * 'a' flag format from the current line until the end of the paragraph.
4784 * Keep the cursor at the same position relative to the text.
4785 * The caller must have saved the cursor line for undo, following ones will be
4786 * saved here.
4787 */
4788 void
4789auto_format(trailblank, prev_line)
4790 int trailblank; /* when TRUE also format with trailing blank */
4791 int prev_line; /* may start in previous line */
4792{
4793 pos_T pos;
4794 colnr_T len;
4795 char_u *old;
4796 char_u *new, *pnew;
4797 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004798 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799
4800 if (!has_format_option(FO_AUTO))
4801 return;
4802
4803 pos = curwin->w_cursor;
4804 old = ml_get_curline();
4805
4806 /* may remove added space */
4807 check_auto_format(FALSE);
4808
4809 /* Don't format in Insert mode when the cursor is on a trailing blank, the
4810 * user might insert normal text next. Also skip formatting when "1" is
4811 * in 'formatoptions' and there is a single character before the cursor.
4812 * Otherwise the line would be broken and when typing another non-white
4813 * next they are not joined back together. */
4814 wasatend = (pos.col == STRLEN(old));
4815 if (*old != NUL && !trailblank && wasatend)
4816 {
4817 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004818 cc = gchar_cursor();
4819 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
4820 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004822 cc = gchar_cursor();
4823 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 {
4825 curwin->w_cursor = pos;
4826 return;
4827 }
4828 curwin->w_cursor = pos;
4829 }
4830
4831#ifdef FEAT_COMMENTS
4832 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
4833 * comments. */
4834 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
4835 && get_leader_len(old, NULL, FALSE) == 0)
4836 return;
4837#endif
4838
4839 /*
4840 * May start formatting in a previous line, so that after "x" a word is
4841 * moved to the previous line if it fits there now. Only when this is not
4842 * the start of a paragraph.
4843 */
4844 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
4845 {
4846 --curwin->w_cursor.lnum;
4847 if (u_save_cursor() == FAIL)
4848 return;
4849 }
4850
4851 /*
4852 * Do the formatting and restore the cursor position. "saved_cursor" will
4853 * be adjusted for the text formatting.
4854 */
4855 saved_cursor = pos;
4856 format_lines((linenr_T)-1);
4857 curwin->w_cursor = saved_cursor;
4858 saved_cursor.lnum = 0;
4859
4860 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
4861 {
4862 /* "cannot happen" */
4863 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4864 coladvance((colnr_T)MAXCOL);
4865 }
4866 else
4867 check_cursor_col();
4868
4869 /* Insert mode: If the cursor is now after the end of the line while it
4870 * previously wasn't, the line was broken. Because of the rule above we
4871 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
4872 * formatted. */
4873 if (!wasatend && has_format_option(FO_WHITE_PAR))
4874 {
4875 new = ml_get_curline();
4876 len = STRLEN(new);
4877 if (curwin->w_cursor.col == len)
4878 {
4879 pnew = vim_strnsave(new, len + 2);
4880 pnew[len] = ' ';
4881 pnew[len + 1] = NUL;
4882 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
4883 /* remove the space later */
4884 did_add_space = TRUE;
4885 }
4886 else
4887 /* may remove added space */
4888 check_auto_format(FALSE);
4889 }
4890
4891 check_cursor();
4892}
4893
4894/*
4895 * When an extra space was added to continue a paragraph for auto-formatting,
4896 * delete it now. The space must be under the cursor, just after the insert
4897 * position.
4898 */
4899 static void
4900check_auto_format(end_insert)
4901 int end_insert; /* TRUE when ending Insert mode */
4902{
4903 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004904 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905
4906 if (did_add_space)
4907 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004908 cc = gchar_cursor();
4909 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910 /* Somehow the space was removed already. */
4911 did_add_space = FALSE;
4912 else
4913 {
4914 if (!end_insert)
4915 {
4916 inc_cursor();
4917 c = gchar_cursor();
4918 dec_cursor();
4919 }
4920 if (c != NUL)
4921 {
4922 /* The space is no longer at the end of the line, delete it. */
4923 del_char(FALSE);
4924 did_add_space = FALSE;
4925 }
4926 }
4927 }
4928}
4929
4930/*
4931 * Find out textwidth to be used for formatting:
4932 * if 'textwidth' option is set, use it
4933 * else if 'wrapmargin' option is set, use W_WIDTH(curwin) - 'wrapmargin'
4934 * if invalid value, use 0.
4935 * Set default to window width (maximum 79) for "gq" operator.
4936 */
4937 int
4938comp_textwidth(ff)
4939 int ff; /* force formatting (for "Q" command) */
4940{
4941 int textwidth;
4942
4943 textwidth = curbuf->b_p_tw;
4944 if (textwidth == 0 && curbuf->b_p_wm)
4945 {
4946 /* The width is the window width minus 'wrapmargin' minus all the
4947 * things that add to the margin. */
4948 textwidth = W_WIDTH(curwin) - curbuf->b_p_wm;
4949#ifdef FEAT_CMDWIN
4950 if (cmdwin_type != 0)
4951 textwidth -= 1;
4952#endif
4953#ifdef FEAT_FOLDING
4954 textwidth -= curwin->w_p_fdc;
4955#endif
4956#ifdef FEAT_SIGNS
4957 if (curwin->w_buffer->b_signlist != NULL
4958# ifdef FEAT_NETBEANS_INTG
4959 || usingNetbeans
4960# endif
4961 )
4962 textwidth -= 1;
4963#endif
4964 if (curwin->w_p_nu)
4965 textwidth -= 8;
4966 }
4967 if (textwidth < 0)
4968 textwidth = 0;
4969 if (ff && textwidth == 0)
4970 {
4971 textwidth = W_WIDTH(curwin) - 1;
4972 if (textwidth > 79)
4973 textwidth = 79;
4974 }
4975 return textwidth;
4976}
4977
4978/*
4979 * Put a character in the redo buffer, for when just after a CTRL-V.
4980 */
4981 static void
4982redo_literal(c)
4983 int c;
4984{
4985 char_u buf[10];
4986
4987 /* Only digits need special treatment. Translate them into a string of
4988 * three digits. */
4989 if (VIM_ISDIGIT(c))
4990 {
4991 sprintf((char *)buf, "%03d", c);
4992 AppendToRedobuff(buf);
4993 }
4994 else
4995 AppendCharToRedobuff(c);
4996}
4997
4998/*
4999 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005000 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 */
5002 static void
5003start_arrow(end_insert_pos)
5004 pos_T *end_insert_pos;
5005{
5006 if (!arrow_used) /* something has been inserted */
5007 {
5008 AppendToRedobuff(ESC_STR);
5009 stop_insert(end_insert_pos, FALSE);
5010 arrow_used = TRUE; /* this means we stopped the current insert */
5011 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00005012#ifdef FEAT_SYN_HL
5013 check_spell_redraw();
5014#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015}
5016
Bram Moolenaar217ad922005-03-20 22:37:15 +00005017#ifdef FEAT_SYN_HL
5018/*
5019 * If we skipped highlighting word at cursor, do it now.
5020 * It may be skipped again, thus reset spell_redraw_lnum first.
5021 */
5022 static void
5023check_spell_redraw()
5024{
5025 if (spell_redraw_lnum != 0)
5026 {
5027 linenr_T lnum = spell_redraw_lnum;
5028
5029 spell_redraw_lnum = 0;
5030 redrawWinline(lnum, FALSE);
5031 }
5032}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005033
5034/*
5035 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
5036 * spelled word, if there is one.
5037 */
5038 static void
5039spell_back_to_badword()
5040{
5041 pos_T tpos = curwin->w_cursor;
5042
Bram Moolenaar81f1ecb2005-08-25 21:27:31 +00005043 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005044 if (curwin->w_cursor.col != tpos.col)
5045 start_arrow(&tpos);
5046}
Bram Moolenaar217ad922005-03-20 22:37:15 +00005047#endif
5048
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049/*
5050 * stop_arrow() is called before a change is made in insert mode.
5051 * If an arrow key has been used, start a new insertion.
5052 * Returns FAIL if undo is impossible, shouldn't insert then.
5053 */
5054 int
5055stop_arrow()
5056{
5057 if (arrow_used)
5058 {
5059 if (u_save_cursor() == OK)
5060 {
5061 arrow_used = FALSE;
5062 ins_need_undo = FALSE;
5063 }
5064 Insstart = curwin->w_cursor; /* new insertion starts here */
5065 Insstart_textlen = linetabsize(ml_get_curline());
5066 ai_col = 0;
5067#ifdef FEAT_VREPLACE
5068 if (State & VREPLACE_FLAG)
5069 {
5070 orig_line_count = curbuf->b_ml.ml_line_count;
5071 vr_lines_changed = 1;
5072 }
5073#endif
5074 ResetRedobuff();
5075 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
5076 }
5077 else if (ins_need_undo)
5078 {
5079 if (u_save_cursor() == OK)
5080 ins_need_undo = FALSE;
5081 }
5082
5083#ifdef FEAT_FOLDING
5084 /* Always open fold at the cursor line when inserting something. */
5085 foldOpenCursor();
5086#endif
5087
5088 return (arrow_used || ins_need_undo ? FAIL : OK);
5089}
5090
5091/*
5092 * do a few things to stop inserting
5093 */
5094 static void
5095stop_insert(end_insert_pos, esc)
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005096 pos_T *end_insert_pos; /* where insert ended */
5097 int esc; /* called by ins_esc() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098{
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005099 int cc;
5100 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101
5102 stop_redo_ins();
5103 replace_flush(); /* abandon replace stack */
5104
5105 /*
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005106 * Save the inserted text for later redo with ^@ and CTRL-A.
5107 * Don't do it when "restart_edit" was set and nothing was inserted,
5108 * otherwise CTRL-O w and then <Left> will clear "last_insert".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 */
Bram Moolenaar83c465c2005-12-16 21:53:56 +00005110 ptr = get_inserted();
5111 if (did_restart_edit == 0 || (ptr != NULL && STRLEN(ptr) > new_insert_skip))
5112 {
5113 vim_free(last_insert);
5114 last_insert = ptr;
5115 last_insert_skip = new_insert_skip;
5116 }
5117 else
5118 vim_free(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119
5120 if (!arrow_used)
5121 {
5122 /* Auto-format now. It may seem strange to do this when stopping an
5123 * insertion (or moving the cursor), but it's required when appending
5124 * a line and having it end in a space. But only do it when something
5125 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005126 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005127 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005128 pos_T tpos = curwin->w_cursor;
5129
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130 /* When the cursor is at the end of the line after a space the
5131 * formatting will move it to the following word. Avoid that by
5132 * moving the cursor onto the space. */
5133 cc = 'x';
5134 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
5135 {
5136 dec_cursor();
5137 cc = gchar_cursor();
5138 if (!vim_iswhite(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005139 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005140 }
5141
5142 auto_format(TRUE, FALSE);
5143
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005144 if (vim_iswhite(cc))
5145 {
5146 if (gchar_cursor() != NUL)
5147 inc_cursor();
5148#ifdef FEAT_VIRTUALEDIT
5149 /* If the cursor is still at the same character, also keep
5150 * the "coladd". */
5151 if (gchar_cursor() == NUL
5152 && curwin->w_cursor.lnum == tpos.lnum
5153 && curwin->w_cursor.col == tpos.col)
5154 curwin->w_cursor.coladd = tpos.coladd;
5155#endif
5156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157 }
5158
5159 /* If a space was inserted for auto-formatting, remove it now. */
5160 check_auto_format(TRUE);
5161
5162 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005163 * of the line, and put the cursor back.
5164 * Do this when ESC was used or moving the cursor up/down. */
5165 if (did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
5166 && curwin->w_cursor.lnum != end_insert_pos->lnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005167 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005168 pos_T tpos = curwin->w_cursor;
5169
5170 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
5172 --curwin->w_cursor.col;
5173 while (cc = gchar_cursor(), vim_iswhite(cc))
5174 (void)del_char(TRUE);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005175 if (curwin->w_cursor.lnum != tpos.lnum)
5176 curwin->w_cursor = tpos;
5177 else if (cc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005178 ++curwin->w_cursor.col; /* put cursor back on the NUL */
5179
5180#ifdef FEAT_VISUAL
5181 /* <C-S-Right> may have started Visual mode, adjust the position for
5182 * deleted characters. */
5183 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
5184 {
5185 cc = STRLEN(ml_get_curline());
5186 if (VIsual.col > (colnr_T)cc)
5187 {
5188 VIsual.col = cc;
5189# ifdef FEAT_VIRTUALEDIT
5190 VIsual.coladd = 0;
5191# endif
5192 }
5193 }
5194#endif
5195 }
5196 }
5197 did_ai = FALSE;
5198#ifdef FEAT_SMARTINDENT
5199 did_si = FALSE;
5200 can_si = FALSE;
5201 can_si_back = FALSE;
5202#endif
5203
5204 /* set '[ and '] to the inserted text */
5205 curbuf->b_op_start = Insstart;
5206 curbuf->b_op_end = *end_insert_pos;
5207}
5208
5209/*
5210 * Set the last inserted text to a single character.
5211 * Used for the replace command.
5212 */
5213 void
5214set_last_insert(c)
5215 int c;
5216{
5217 char_u *s;
5218
5219 vim_free(last_insert);
5220#ifdef FEAT_MBYTE
5221 last_insert = alloc(MB_MAXBYTES * 3 + 5);
5222#else
5223 last_insert = alloc(6);
5224#endif
5225 if (last_insert != NULL)
5226 {
5227 s = last_insert;
5228 /* Use the CTRL-V only when entering a special char */
5229 if (c < ' ' || c == DEL)
5230 *s++ = Ctrl_V;
5231 s = add_char2buf(c, s);
5232 *s++ = ESC;
5233 *s++ = NUL;
5234 last_insert_skip = 0;
5235 }
5236}
5237
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00005238#if defined(EXITFREE) || defined(PROTO)
5239 void
5240free_last_insert()
5241{
5242 vim_free(last_insert);
5243 last_insert = NULL;
5244}
5245#endif
5246
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247/*
5248 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
5249 * and CSI. Handle multi-byte characters.
5250 * Returns a pointer to after the added bytes.
5251 */
5252 char_u *
5253add_char2buf(c, s)
5254 int c;
5255 char_u *s;
5256{
5257#ifdef FEAT_MBYTE
5258 char_u temp[MB_MAXBYTES];
5259 int i;
5260 int len;
5261
5262 len = (*mb_char2bytes)(c, temp);
5263 for (i = 0; i < len; ++i)
5264 {
5265 c = temp[i];
5266#endif
5267 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
5268 if (c == K_SPECIAL)
5269 {
5270 *s++ = K_SPECIAL;
5271 *s++ = KS_SPECIAL;
5272 *s++ = KE_FILLER;
5273 }
5274#ifdef FEAT_GUI
5275 else if (c == CSI)
5276 {
5277 *s++ = CSI;
5278 *s++ = KS_EXTRA;
5279 *s++ = (int)KE_CSI;
5280 }
5281#endif
5282 else
5283 *s++ = c;
5284#ifdef FEAT_MBYTE
5285 }
5286#endif
5287 return s;
5288}
5289
5290/*
5291 * move cursor to start of line
5292 * if flags & BL_WHITE move to first non-white
5293 * if flags & BL_SOL move to first non-white if startofline is set,
5294 * otherwise keep "curswant" column
5295 * if flags & BL_FIX don't leave the cursor on a NUL.
5296 */
5297 void
5298beginline(flags)
5299 int flags;
5300{
5301 if ((flags & BL_SOL) && !p_sol)
5302 coladvance(curwin->w_curswant);
5303 else
5304 {
5305 curwin->w_cursor.col = 0;
5306#ifdef FEAT_VIRTUALEDIT
5307 curwin->w_cursor.coladd = 0;
5308#endif
5309
5310 if (flags & (BL_WHITE | BL_SOL))
5311 {
5312 char_u *ptr;
5313
5314 for (ptr = ml_get_curline(); vim_iswhite(*ptr)
5315 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
5316 ++curwin->w_cursor.col;
5317 }
5318 curwin->w_set_curswant = TRUE;
5319 }
5320}
5321
5322/*
5323 * oneright oneleft cursor_down cursor_up
5324 *
5325 * Move one char {right,left,down,up}.
5326 * Doesn't move onto the NUL past the end of the line.
5327 * Return OK when successful, FAIL when we hit a line of file boundary.
5328 */
5329
5330 int
5331oneright()
5332{
5333 char_u *ptr;
5334#ifdef FEAT_MBYTE
5335 int l;
5336#endif
5337
5338#ifdef FEAT_VIRTUALEDIT
5339 if (virtual_active())
5340 {
5341 pos_T prevpos = curwin->w_cursor;
5342
5343 /* Adjust for multi-wide char (excluding TAB) */
5344 ptr = ml_get_cursor();
5345 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(
5346#ifdef FEAT_MBYTE
5347 (*mb_ptr2char)(ptr)
5348#else
5349 *ptr
5350#endif
5351 ))
5352 ? ptr2cells(ptr) : 1));
5353 curwin->w_set_curswant = TRUE;
5354 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
5355 return (prevpos.col != curwin->w_cursor.col
5356 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
5357 }
5358#endif
5359
5360 ptr = ml_get_cursor();
5361#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005362 if (has_mbyte && (l = (*mb_ptr2len)(ptr)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363 {
5364 /* The character under the cursor is a multi-byte character, move
5365 * several bytes right, but don't end up on the NUL. */
5366 if (ptr[l] == NUL)
5367 return FAIL;
5368 curwin->w_cursor.col += l;
5369 }
5370 else
5371#endif
5372 {
5373 if (*ptr++ == NUL || *ptr == NUL)
5374 return FAIL;
5375 ++curwin->w_cursor.col;
5376 }
5377
5378 curwin->w_set_curswant = TRUE;
5379 return OK;
5380}
5381
5382 int
5383oneleft()
5384{
5385#ifdef FEAT_VIRTUALEDIT
5386 if (virtual_active())
5387 {
5388 int width;
5389 int v = getviscol();
5390
5391 if (v == 0)
5392 return FAIL;
5393
5394# ifdef FEAT_LINEBREAK
5395 /* We might get stuck on 'showbreak', skip over it. */
5396 width = 1;
5397 for (;;)
5398 {
5399 coladvance(v - width);
5400 /* getviscol() is slow, skip it when 'showbreak' is empty and
5401 * there are no multi-byte characters */
5402 if ((*p_sbr == NUL
5403# ifdef FEAT_MBYTE
5404 && !has_mbyte
5405# endif
5406 ) || getviscol() < v)
5407 break;
5408 ++width;
5409 }
5410# else
5411 coladvance(v - 1);
5412# endif
5413
5414 if (curwin->w_cursor.coladd == 1)
5415 {
5416 char_u *ptr;
5417
5418 /* Adjust for multi-wide char (not a TAB) */
5419 ptr = ml_get_cursor();
5420 if (*ptr != TAB && vim_isprintc(
5421# ifdef FEAT_MBYTE
5422 (*mb_ptr2char)(ptr)
5423# else
5424 *ptr
5425# endif
5426 ) && ptr2cells(ptr) > 1)
5427 curwin->w_cursor.coladd = 0;
5428 }
5429
5430 curwin->w_set_curswant = TRUE;
5431 return OK;
5432 }
5433#endif
5434
5435 if (curwin->w_cursor.col == 0)
5436 return FAIL;
5437
5438 curwin->w_set_curswant = TRUE;
5439 --curwin->w_cursor.col;
5440
5441#ifdef FEAT_MBYTE
5442 /* if the character on the left of the current cursor is a multi-byte
5443 * character, move to its first byte */
5444 if (has_mbyte)
5445 mb_adjust_cursor();
5446#endif
5447 return OK;
5448}
5449
5450 int
5451cursor_up(n, upd_topline)
5452 long n;
5453 int upd_topline; /* When TRUE: update topline */
5454{
5455 linenr_T lnum;
5456
5457 if (n > 0)
5458 {
5459 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00005460 /* This fails if the cursor is already in the first line or the count
5461 * is larger than the line number and '-' is in 'cpoptions' */
5462 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 return FAIL;
5464 if (n >= lnum)
5465 lnum = 1;
5466 else
5467#ifdef FEAT_FOLDING
5468 if (hasAnyFolding(curwin))
5469 {
5470 /*
5471 * Count each sequence of folded lines as one logical line.
5472 */
5473 /* go to the the start of the current fold */
5474 (void)hasFolding(lnum, &lnum, NULL);
5475
5476 while (n--)
5477 {
5478 /* move up one line */
5479 --lnum;
5480 if (lnum <= 1)
5481 break;
5482 /* If we entered a fold, move to the beginning, unless in
5483 * Insert mode or when 'foldopen' contains "all": it will open
5484 * in a moment. */
5485 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
5486 (void)hasFolding(lnum, &lnum, NULL);
5487 }
5488 if (lnum < 1)
5489 lnum = 1;
5490 }
5491 else
5492#endif
5493 lnum -= n;
5494 curwin->w_cursor.lnum = lnum;
5495 }
5496
5497 /* try to advance to the column we want to be at */
5498 coladvance(curwin->w_curswant);
5499
5500 if (upd_topline)
5501 update_topline(); /* make sure curwin->w_topline is valid */
5502
5503 return OK;
5504}
5505
5506/*
5507 * Cursor down a number of logical lines.
5508 */
5509 int
5510cursor_down(n, upd_topline)
5511 long n;
5512 int upd_topline; /* When TRUE: update topline */
5513{
5514 linenr_T lnum;
5515
5516 if (n > 0)
5517 {
5518 lnum = curwin->w_cursor.lnum;
5519#ifdef FEAT_FOLDING
5520 /* Move to last line of fold, will fail if it's the end-of-file. */
5521 (void)hasFolding(lnum, NULL, &lnum);
5522#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00005523 /* This fails if the cursor is already in the last line or would move
5524 * beyound the last line and '-' is in 'cpoptions' */
5525 if (lnum >= curbuf->b_ml.ml_line_count
5526 || (lnum + n > curbuf->b_ml.ml_line_count
5527 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005528 return FAIL;
5529 if (lnum + n >= curbuf->b_ml.ml_line_count)
5530 lnum = curbuf->b_ml.ml_line_count;
5531 else
5532#ifdef FEAT_FOLDING
5533 if (hasAnyFolding(curwin))
5534 {
5535 linenr_T last;
5536
5537 /* count each sequence of folded lines as one logical line */
5538 while (n--)
5539 {
5540 if (hasFolding(lnum, NULL, &last))
5541 lnum = last + 1;
5542 else
5543 ++lnum;
5544 if (lnum >= curbuf->b_ml.ml_line_count)
5545 break;
5546 }
5547 if (lnum > curbuf->b_ml.ml_line_count)
5548 lnum = curbuf->b_ml.ml_line_count;
5549 }
5550 else
5551#endif
5552 lnum += n;
5553 curwin->w_cursor.lnum = lnum;
5554 }
5555
5556 /* try to advance to the column we want to be at */
5557 coladvance(curwin->w_curswant);
5558
5559 if (upd_topline)
5560 update_topline(); /* make sure curwin->w_topline is valid */
5561
5562 return OK;
5563}
5564
5565/*
5566 * Stuff the last inserted text in the read buffer.
5567 * Last_insert actually is a copy of the redo buffer, so we
5568 * first have to remove the command.
5569 */
5570 int
5571stuff_inserted(c, count, no_esc)
5572 int c; /* Command character to be inserted */
5573 long count; /* Repeat this many times */
5574 int no_esc; /* Don't add an ESC at the end */
5575{
5576 char_u *esc_ptr;
5577 char_u *ptr;
5578 char_u *last_ptr;
5579 char_u last = NUL;
5580
5581 ptr = get_last_insert();
5582 if (ptr == NULL)
5583 {
5584 EMSG(_(e_noinstext));
5585 return FAIL;
5586 }
5587
5588 /* may want to stuff the command character, to start Insert mode */
5589 if (c != NUL)
5590 stuffcharReadbuff(c);
5591 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
5592 *esc_ptr = NUL; /* remove the ESC */
5593
5594 /* when the last char is either "0" or "^" it will be quoted if no ESC
5595 * comes after it OR if it will inserted more than once and "ptr"
5596 * starts with ^D. -- Acevedo
5597 */
5598 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
5599 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
5600 && (no_esc || (*ptr == Ctrl_D && count > 1)))
5601 {
5602 last = *last_ptr;
5603 *last_ptr = NUL;
5604 }
5605
5606 do
5607 {
5608 stuffReadbuff(ptr);
5609 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
5610 if (last)
5611 stuffReadbuff((char_u *)(last == '0'
5612 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
5613 : IF_EB("\026^", CTRL_V_STR "^")));
5614 }
5615 while (--count > 0);
5616
5617 if (last)
5618 *last_ptr = last;
5619
5620 if (esc_ptr != NULL)
5621 *esc_ptr = ESC; /* put the ESC back */
5622
5623 /* may want to stuff a trailing ESC, to get out of Insert mode */
5624 if (!no_esc)
5625 stuffcharReadbuff(ESC);
5626
5627 return OK;
5628}
5629
5630 char_u *
5631get_last_insert()
5632{
5633 if (last_insert == NULL)
5634 return NULL;
5635 return last_insert + last_insert_skip;
5636}
5637
5638/*
5639 * Get last inserted string, and remove trailing <Esc>.
5640 * Returns pointer to allocated memory (must be freed) or NULL.
5641 */
5642 char_u *
5643get_last_insert_save()
5644{
5645 char_u *s;
5646 int len;
5647
5648 if (last_insert == NULL)
5649 return NULL;
5650 s = vim_strsave(last_insert + last_insert_skip);
5651 if (s != NULL)
5652 {
5653 len = (int)STRLEN(s);
5654 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
5655 s[len - 1] = NUL;
5656 }
5657 return s;
5658}
5659
5660/*
5661 * Check the word in front of the cursor for an abbreviation.
5662 * Called when the non-id character "c" has been entered.
5663 * When an abbreviation is recognized it is removed from the text and
5664 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
5665 */
5666 static int
5667echeck_abbr(c)
5668 int c;
5669{
5670 /* Don't check for abbreviation in paste mode, when disabled and just
5671 * after moving around with cursor keys. */
5672 if (p_paste || no_abbr || arrow_used)
5673 return FALSE;
5674
5675 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
5676 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
5677}
5678
5679/*
5680 * replace-stack functions
5681 *
5682 * When replacing characters, the replaced characters are remembered for each
5683 * new character. This is used to re-insert the old text when backspacing.
5684 *
5685 * There is a NUL headed list of characters for each character that is
5686 * currently in the file after the insertion point. When BS is used, one NUL
5687 * headed list is put back for the deleted character.
5688 *
5689 * For a newline, there are two NUL headed lists. One contains the characters
5690 * that the NL replaced. The extra one stores the characters after the cursor
5691 * that were deleted (always white space).
5692 *
5693 * Replace_offset is normally 0, in which case replace_push will add a new
5694 * character at the end of the stack. If replace_offset is not 0, that many
5695 * characters will be left on the stack above the newly inserted character.
5696 */
5697
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00005698static char_u *replace_stack = NULL;
5699static long replace_stack_nr = 0; /* next entry in replace stack */
5700static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701
5702 void
5703replace_push(c)
5704 int c; /* character that is replaced (NUL is none) */
5705{
5706 char_u *p;
5707
5708 if (replace_stack_nr < replace_offset) /* nothing to do */
5709 return;
5710 if (replace_stack_len <= replace_stack_nr)
5711 {
5712 replace_stack_len += 50;
5713 p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
5714 if (p == NULL) /* out of memory */
5715 {
5716 replace_stack_len -= 50;
5717 return;
5718 }
5719 if (replace_stack != NULL)
5720 {
5721 mch_memmove(p, replace_stack,
5722 (size_t)(replace_stack_nr * sizeof(char_u)));
5723 vim_free(replace_stack);
5724 }
5725 replace_stack = p;
5726 }
5727 p = replace_stack + replace_stack_nr - replace_offset;
5728 if (replace_offset)
5729 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
5730 *p = c;
5731 ++replace_stack_nr;
5732}
5733
5734/*
5735 * call replace_push(c) with replace_offset set to the first NUL.
5736 */
5737 static void
5738replace_push_off(c)
5739 int c;
5740{
5741 char_u *p;
5742
5743 p = replace_stack + replace_stack_nr;
5744 for (replace_offset = 1; replace_offset < replace_stack_nr;
5745 ++replace_offset)
5746 if (*--p == NUL)
5747 break;
5748 replace_push(c);
5749 replace_offset = 0;
5750}
5751
5752/*
5753 * Pop one item from the replace stack.
5754 * return -1 if stack empty
5755 * return replaced character or NUL otherwise
5756 */
5757 static int
5758replace_pop()
5759{
5760 if (replace_stack_nr == 0)
5761 return -1;
5762 return (int)replace_stack[--replace_stack_nr];
5763}
5764
5765/*
5766 * Join the top two items on the replace stack. This removes to "off"'th NUL
5767 * encountered.
5768 */
5769 static void
5770replace_join(off)
5771 int off; /* offset for which NUL to remove */
5772{
5773 int i;
5774
5775 for (i = replace_stack_nr; --i >= 0; )
5776 if (replace_stack[i] == NUL && off-- <= 0)
5777 {
5778 --replace_stack_nr;
5779 mch_memmove(replace_stack + i, replace_stack + i + 1,
5780 (size_t)(replace_stack_nr - i));
5781 return;
5782 }
5783}
5784
5785/*
5786 * Pop bytes from the replace stack until a NUL is found, and insert them
5787 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
5788 */
5789 static void
5790replace_pop_ins()
5791{
5792 int cc;
5793 int oldState = State;
5794
5795 State = NORMAL; /* don't want REPLACE here */
5796 while ((cc = replace_pop()) > 0)
5797 {
5798#ifdef FEAT_MBYTE
5799 mb_replace_pop_ins(cc);
5800#else
5801 ins_char(cc);
5802#endif
5803 dec_cursor();
5804 }
5805 State = oldState;
5806}
5807
5808#ifdef FEAT_MBYTE
5809/*
5810 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
5811 * indicates a multi-byte char, pop the other bytes too.
5812 */
5813 static void
5814mb_replace_pop_ins(cc)
5815 int cc;
5816{
5817 int n;
5818 char_u buf[MB_MAXBYTES];
5819 int i;
5820 int c;
5821
5822 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
5823 {
5824 buf[0] = cc;
5825 for (i = 1; i < n; ++i)
5826 buf[i] = replace_pop();
5827 ins_bytes_len(buf, n);
5828 }
5829 else
5830 ins_char(cc);
5831
5832 if (enc_utf8)
5833 /* Handle composing chars. */
5834 for (;;)
5835 {
5836 c = replace_pop();
5837 if (c == -1) /* stack empty */
5838 break;
5839 if ((n = MB_BYTE2LEN(c)) == 1)
5840 {
5841 /* Not a multi-byte char, put it back. */
5842 replace_push(c);
5843 break;
5844 }
5845 else
5846 {
5847 buf[0] = c;
5848 for (i = 1; i < n; ++i)
5849 buf[i] = replace_pop();
5850 if (utf_iscomposing(utf_ptr2char(buf)))
5851 ins_bytes_len(buf, n);
5852 else
5853 {
5854 /* Not a composing char, put it back. */
5855 for (i = n - 1; i >= 0; --i)
5856 replace_push(buf[i]);
5857 break;
5858 }
5859 }
5860 }
5861}
5862#endif
5863
5864/*
5865 * make the replace stack empty
5866 * (called when exiting replace mode)
5867 */
5868 static void
5869replace_flush()
5870{
5871 vim_free(replace_stack);
5872 replace_stack = NULL;
5873 replace_stack_len = 0;
5874 replace_stack_nr = 0;
5875}
5876
5877/*
5878 * Handle doing a BS for one character.
5879 * cc < 0: replace stack empty, just move cursor
5880 * cc == 0: character was inserted, delete it
5881 * cc > 0: character was replaced, put cc (first byte of original char) back
5882 * and check for more characters to be put back
5883 */
5884 static void
5885replace_do_bs()
5886{
5887 int cc;
5888#ifdef FEAT_VREPLACE
5889 int orig_len = 0;
5890 int ins_len;
5891 int orig_vcols = 0;
5892 colnr_T start_vcol;
5893 char_u *p;
5894 int i;
5895 int vcol;
5896#endif
5897
5898 cc = replace_pop();
5899 if (cc > 0)
5900 {
5901#ifdef FEAT_VREPLACE
5902 if (State & VREPLACE_FLAG)
5903 {
5904 /* Get the number of screen cells used by the character we are
5905 * going to delete. */
5906 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
5907 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
5908 }
5909#endif
5910#ifdef FEAT_MBYTE
5911 if (has_mbyte)
5912 {
5913 del_char(FALSE);
5914# ifdef FEAT_VREPLACE
5915 if (State & VREPLACE_FLAG)
5916 orig_len = STRLEN(ml_get_cursor());
5917# endif
5918 replace_push(cc);
5919 }
5920 else
5921#endif
5922 {
5923 pchar_cursor(cc);
5924#ifdef FEAT_VREPLACE
5925 if (State & VREPLACE_FLAG)
5926 orig_len = STRLEN(ml_get_cursor()) - 1;
5927#endif
5928 }
5929 replace_pop_ins();
5930
5931#ifdef FEAT_VREPLACE
5932 if (State & VREPLACE_FLAG)
5933 {
5934 /* Get the number of screen cells used by the inserted characters */
5935 p = ml_get_cursor();
5936 ins_len = STRLEN(p) - orig_len;
5937 vcol = start_vcol;
5938 for (i = 0; i < ins_len; ++i)
5939 {
5940 vcol += chartabsize(p + i, vcol);
5941#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005942 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943#endif
5944 }
5945 vcol -= start_vcol;
5946
5947 /* Delete spaces that were inserted after the cursor to keep the
5948 * text aligned. */
5949 curwin->w_cursor.col += ins_len;
5950 while (vcol > orig_vcols && gchar_cursor() == ' ')
5951 {
5952 del_char(FALSE);
5953 ++orig_vcols;
5954 }
5955 curwin->w_cursor.col -= ins_len;
5956 }
5957#endif
5958
5959 /* mark the buffer as changed and prepare for displaying */
5960 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
5961 }
5962 else if (cc == 0)
5963 (void)del_char(FALSE);
5964}
5965
5966#ifdef FEAT_CINDENT
5967/*
5968 * Return TRUE if C-indenting is on.
5969 */
5970 static int
5971cindent_on()
5972{
5973 return (!p_paste && (curbuf->b_p_cin
5974# ifdef FEAT_EVAL
5975 || *curbuf->b_p_inde != NUL
5976# endif
5977 ));
5978}
5979#endif
5980
5981#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
5982/*
5983 * Re-indent the current line, based on the current contents of it and the
5984 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
5985 * confused what all the part that handles Control-T is doing that I'm not.
5986 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
5987 */
5988
5989 void
5990fixthisline(get_the_indent)
5991 int (*get_the_indent) __ARGS((void));
5992{
5993 change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
5994 if (linewhite(curwin->w_cursor.lnum))
5995 did_ai = TRUE; /* delete the indent if the line stays empty */
5996}
5997
5998 void
5999fix_indent()
6000{
6001 if (p_paste)
6002 return;
6003# ifdef FEAT_LISP
6004 if (curbuf->b_p_lisp && curbuf->b_p_ai)
6005 fixthisline(get_lisp_indent);
6006# endif
6007# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
6008 else
6009# endif
6010# ifdef FEAT_CINDENT
6011 if (cindent_on())
6012 do_c_expr_indent();
6013# endif
6014}
6015
6016#endif
6017
6018#ifdef FEAT_CINDENT
6019/*
6020 * return TRUE if 'cinkeys' contains the key "keytyped",
6021 * when == '*': Only if key is preceded with '*' (indent before insert)
6022 * when == '!': Only if key is prededed with '!' (don't insert)
6023 * when == ' ': Only if key is not preceded with '*'(indent afterwards)
6024 *
6025 * "keytyped" can have a few special values:
6026 * KEY_OPEN_FORW
6027 * KEY_OPEN_BACK
6028 * KEY_COMPLETE just finished completion.
6029 *
6030 * If line_is_empty is TRUE accept keys with '0' before them.
6031 */
6032 int
6033in_cinkeys(keytyped, when, line_is_empty)
6034 int keytyped;
6035 int when;
6036 int line_is_empty;
6037{
6038 char_u *look;
6039 int try_match;
6040 int try_match_word;
6041 char_u *p;
6042 char_u *line;
6043 int icase;
6044 int i;
6045
6046#ifdef FEAT_EVAL
6047 if (*curbuf->b_p_inde != NUL)
6048 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
6049 else
6050#endif
6051 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
6052 while (*look)
6053 {
6054 /*
6055 * Find out if we want to try a match with this key, depending on
6056 * 'when' and a '*' or '!' before the key.
6057 */
6058 switch (when)
6059 {
6060 case '*': try_match = (*look == '*'); break;
6061 case '!': try_match = (*look == '!'); break;
6062 default: try_match = (*look != '*'); break;
6063 }
6064 if (*look == '*' || *look == '!')
6065 ++look;
6066
6067 /*
6068 * If there is a '0', only accept a match if the line is empty.
6069 * But may still match when typing last char of a word.
6070 */
6071 if (*look == '0')
6072 {
6073 try_match_word = try_match;
6074 if (!line_is_empty)
6075 try_match = FALSE;
6076 ++look;
6077 }
6078 else
6079 try_match_word = FALSE;
6080
6081 /*
6082 * does it look like a control character?
6083 */
6084 if (*look == '^'
6085#ifdef EBCDIC
6086 && (Ctrl_chr(look[1]) != 0)
6087#else
6088 && look[1] >= '?' && look[1] <= '_'
6089#endif
6090 )
6091 {
6092 if (try_match && keytyped == Ctrl_chr(look[1]))
6093 return TRUE;
6094 look += 2;
6095 }
6096 /*
6097 * 'o' means "o" command, open forward.
6098 * 'O' means "O" command, open backward.
6099 */
6100 else if (*look == 'o')
6101 {
6102 if (try_match && keytyped == KEY_OPEN_FORW)
6103 return TRUE;
6104 ++look;
6105 }
6106 else if (*look == 'O')
6107 {
6108 if (try_match && keytyped == KEY_OPEN_BACK)
6109 return TRUE;
6110 ++look;
6111 }
6112
6113 /*
6114 * 'e' means to check for "else" at start of line and just before the
6115 * cursor.
6116 */
6117 else if (*look == 'e')
6118 {
6119 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
6120 {
6121 p = ml_get_curline();
6122 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
6123 STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
6124 return TRUE;
6125 }
6126 ++look;
6127 }
6128
6129 /*
6130 * ':' only causes an indent if it is at the end of a label or case
6131 * statement, or when it was before typing the ':' (to fix
6132 * class::method for C++).
6133 */
6134 else if (*look == ':')
6135 {
6136 if (try_match && keytyped == ':')
6137 {
6138 p = ml_get_curline();
6139 if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
6140 return TRUE;
6141 if (curwin->w_cursor.col > 2
6142 && p[curwin->w_cursor.col - 1] == ':'
6143 && p[curwin->w_cursor.col - 2] == ':')
6144 {
6145 p[curwin->w_cursor.col - 1] = ' ';
6146 i = (cin_iscase(p) || cin_isscopedecl(p)
6147 || cin_islabel(30));
6148 p = ml_get_curline();
6149 p[curwin->w_cursor.col - 1] = ':';
6150 if (i)
6151 return TRUE;
6152 }
6153 }
6154 ++look;
6155 }
6156
6157
6158 /*
6159 * Is it a key in <>, maybe?
6160 */
6161 else if (*look == '<')
6162 {
6163 if (try_match)
6164 {
6165 /*
6166 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
6167 * <:> and <!> so that people can re-indent on o, O, e, 0, <,
6168 * >, *, : and ! keys if they really really want to.
6169 */
6170 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
6171 && keytyped == look[1])
6172 return TRUE;
6173
6174 if (keytyped == get_special_key_code(look + 1))
6175 return TRUE;
6176 }
6177 while (*look && *look != '>')
6178 look++;
6179 while (*look == '>')
6180 look++;
6181 }
6182
6183 /*
6184 * Is it a word: "=word"?
6185 */
6186 else if (*look == '=' && look[1] != ',' && look[1] != NUL)
6187 {
6188 ++look;
6189 if (*look == '~')
6190 {
6191 icase = TRUE;
6192 ++look;
6193 }
6194 else
6195 icase = FALSE;
6196 p = vim_strchr(look, ',');
6197 if (p == NULL)
6198 p = look + STRLEN(look);
6199 if ((try_match || try_match_word)
6200 && curwin->w_cursor.col >= (colnr_T)(p - look))
6201 {
6202 int match = FALSE;
6203
6204#ifdef FEAT_INS_EXPAND
6205 if (keytyped == KEY_COMPLETE)
6206 {
6207 char_u *s;
6208
6209 /* Just completed a word, check if it starts with "look".
6210 * search back for the start of a word. */
6211 line = ml_get_curline();
6212# ifdef FEAT_MBYTE
6213 if (has_mbyte)
6214 {
6215 char_u *n;
6216
6217 for (s = line + curwin->w_cursor.col; s > line; s = n)
6218 {
6219 n = mb_prevptr(line, s);
6220 if (!vim_iswordp(n))
6221 break;
6222 }
6223 }
6224 else
6225# endif
6226 for (s = line + curwin->w_cursor.col; s > line; --s)
6227 if (!vim_iswordc(s[-1]))
6228 break;
6229 if (s + (p - look) <= line + curwin->w_cursor.col
6230 && (icase
6231 ? MB_STRNICMP(s, look, p - look)
6232 : STRNCMP(s, look, p - look)) == 0)
6233 match = TRUE;
6234 }
6235 else
6236#endif
6237 /* TODO: multi-byte */
6238 if (keytyped == (int)p[-1] || (icase && keytyped < 256
6239 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
6240 {
6241 line = ml_get_cursor();
6242 if ((curwin->w_cursor.col == (colnr_T)(p - look)
6243 || !vim_iswordc(line[-(p - look) - 1]))
6244 && (icase
6245 ? MB_STRNICMP(line - (p - look), look, p - look)
6246 : STRNCMP(line - (p - look), look, p - look))
6247 == 0)
6248 match = TRUE;
6249 }
6250 if (match && try_match_word && !try_match)
6251 {
6252 /* "0=word": Check if there are only blanks before the
6253 * word. */
6254 line = ml_get_curline();
6255 if ((int)(skipwhite(line) - line) !=
6256 (int)(curwin->w_cursor.col - (p - look)))
6257 match = FALSE;
6258 }
6259 if (match)
6260 return TRUE;
6261 }
6262 look = p;
6263 }
6264
6265 /*
6266 * ok, it's a boring generic character.
6267 */
6268 else
6269 {
6270 if (try_match && *look == keytyped)
6271 return TRUE;
6272 ++look;
6273 }
6274
6275 /*
6276 * Skip over ", ".
6277 */
6278 look = skip_to_option_part(look);
6279 }
6280 return FALSE;
6281}
6282#endif /* FEAT_CINDENT */
6283
6284#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
6285/*
6286 * Map Hebrew keyboard when in hkmap mode.
6287 */
6288 int
6289hkmap(c)
6290 int c;
6291{
6292 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
6293 {
6294 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
6295 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
6296 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
6297 static char_u map[26] =
6298 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
6299 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
6300 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
6301 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
6302 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
6303 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
6304 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
6305 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
6306 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
6307
6308 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
6309 return (int)(map[CharOrd(c)] - 1 + p_aleph);
6310 /* '-1'='sofit' */
6311 else if (c == 'x')
6312 return 'X';
6313 else if (c == 'q')
6314 return '\''; /* {geresh}={'} */
6315 else if (c == 246)
6316 return ' '; /* \"o --> ' ' for a german keyboard */
6317 else if (c == 228)
6318 return ' '; /* \"a --> ' ' -- / -- */
6319 else if (c == 252)
6320 return ' '; /* \"u --> ' ' -- / -- */
6321#ifdef EBCDIC
6322 else if (islower(c))
6323#else
6324 /* NOTE: islower() does not do the right thing for us on Linux so we
6325 * do this the same was as 5.7 and previous, so it works correctly on
6326 * all systems. Specifically, the e.g. Delete and Arrow keys are
6327 * munged and won't work if e.g. searching for Hebrew text.
6328 */
6329 else if (c >= 'a' && c <= 'z')
6330#endif
6331 return (int)(map[CharOrdLow(c)] + p_aleph);
6332 else
6333 return c;
6334 }
6335 else
6336 {
6337 switch (c)
6338 {
6339 case '`': return ';';
6340 case '/': return '.';
6341 case '\'': return ',';
6342 case 'q': return '/';
6343 case 'w': return '\'';
6344
6345 /* Hebrew letters - set offset from 'a' */
6346 case ',': c = '{'; break;
6347 case '.': c = 'v'; break;
6348 case ';': c = 't'; break;
6349 default: {
6350 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
6351
6352#ifdef EBCDIC
6353 /* see note about islower() above */
6354 if (!islower(c))
6355#else
6356 if (c < 'a' || c > 'z')
6357#endif
6358 return c;
6359 c = str[CharOrdLow(c)];
6360 break;
6361 }
6362 }
6363
6364 return (int)(CharOrdLow(c) + p_aleph);
6365 }
6366}
6367#endif
6368
6369 static void
6370ins_reg()
6371{
6372 int need_redraw = FALSE;
6373 int regname;
6374 int literally = 0;
6375
6376 /*
6377 * If we are going to wait for a character, show a '"'.
6378 */
6379 pc_status = PC_STATUS_UNSET;
6380 if (redrawing() && !char_avail())
6381 {
6382 /* may need to redraw when no more chars available now */
6383 ins_redraw();
6384
6385 edit_putchar('"', TRUE);
6386#ifdef FEAT_CMDL_INFO
6387 add_to_showcmd_c(Ctrl_R);
6388#endif
6389 }
6390
6391#ifdef USE_ON_FLY_SCROLL
6392 dont_scroll = TRUE; /* disallow scrolling here */
6393#endif
6394
6395 /*
6396 * Don't map the register name. This also prevents the mode message to be
6397 * deleted when ESC is hit.
6398 */
6399 ++no_mapping;
6400 regname = safe_vgetc();
6401#ifdef FEAT_LANGMAP
6402 LANGMAP_ADJUST(regname, TRUE);
6403#endif
6404 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
6405 {
6406 /* Get a third key for literal register insertion */
6407 literally = regname;
6408#ifdef FEAT_CMDL_INFO
6409 add_to_showcmd_c(literally);
6410#endif
6411 regname = safe_vgetc();
6412#ifdef FEAT_LANGMAP
6413 LANGMAP_ADJUST(regname, TRUE);
6414#endif
6415 }
6416 --no_mapping;
6417
6418#ifdef FEAT_EVAL
6419 /*
6420 * Don't call u_sync() while getting the expression,
6421 * evaluating it or giving an error message for it!
6422 */
6423 ++no_u_sync;
6424 if (regname == '=')
6425 {
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006426# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006427 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006428# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006429 regname = get_expr_register();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006430# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431 /* Restore the Input Method. */
6432 if (im_on)
6433 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006434# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00006436 if (regname == NUL || !valid_yank_reg(regname, FALSE))
6437 {
6438 vim_beep();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00006440 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441 else
6442 {
6443#endif
6444 if (literally == Ctrl_O || literally == Ctrl_P)
6445 {
6446 /* Append the command to the redo buffer. */
6447 AppendCharToRedobuff(Ctrl_R);
6448 AppendCharToRedobuff(literally);
6449 AppendCharToRedobuff(regname);
6450
6451 do_put(regname, BACKWARD, 1L,
6452 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
6453 }
6454 else if (insert_reg(regname, literally) == FAIL)
6455 {
6456 vim_beep();
6457 need_redraw = TRUE; /* remove the '"' */
6458 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006459 else if (stop_insert_mode)
6460 /* When the '=' register was used and a function was invoked that
6461 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
6462 * insert anything, need to remove the '"' */
6463 need_redraw = TRUE;
6464
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465#ifdef FEAT_EVAL
6466 }
6467 --no_u_sync;
6468#endif
6469#ifdef FEAT_CMDL_INFO
6470 clear_showcmd();
6471#endif
6472
6473 /* If the inserted register is empty, we need to remove the '"' */
6474 if (need_redraw || stuff_empty())
6475 edit_unputchar();
6476}
6477
6478/*
6479 * CTRL-G commands in Insert mode.
6480 */
6481 static void
6482ins_ctrl_g()
6483{
6484 int c;
6485
6486#ifdef FEAT_INS_EXPAND
6487 /* Right after CTRL-X the cursor will be after the ruler. */
6488 setcursor();
6489#endif
6490
6491 /*
6492 * Don't map the second key. This also prevents the mode message to be
6493 * deleted when ESC is hit.
6494 */
6495 ++no_mapping;
6496 c = safe_vgetc();
6497 --no_mapping;
6498 switch (c)
6499 {
6500 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
6501 case K_UP:
6502 case Ctrl_K:
6503 case 'k': ins_up(TRUE);
6504 break;
6505
6506 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
6507 case K_DOWN:
6508 case Ctrl_J:
6509 case 'j': ins_down(TRUE);
6510 break;
6511
6512 /* CTRL-G u: start new undoable edit */
6513 case 'u': u_sync();
6514 ins_need_undo = TRUE;
6515 break;
6516
6517 /* Unknown CTRL-G command, reserved for future expansion. */
6518 default: vim_beep();
6519 }
6520}
6521
6522/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006523 * CTRL-^ in Insert mode.
6524 */
6525 static void
6526ins_ctrl_hat()
6527{
6528 if (map_to_exists_mode((char_u *)"", LANGMAP))
6529 {
6530 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
6531 if (State & LANGMAP)
6532 {
6533 curbuf->b_p_iminsert = B_IMODE_NONE;
6534 State &= ~LANGMAP;
6535 }
6536 else
6537 {
6538 curbuf->b_p_iminsert = B_IMODE_LMAP;
6539 State |= LANGMAP;
6540#ifdef USE_IM_CONTROL
6541 im_set_active(FALSE);
6542#endif
6543 }
6544 }
6545#ifdef USE_IM_CONTROL
6546 else
6547 {
6548 /* There are no ":lmap" mappings, toggle IM */
6549 if (im_get_status())
6550 {
6551 curbuf->b_p_iminsert = B_IMODE_NONE;
6552 im_set_active(FALSE);
6553 }
6554 else
6555 {
6556 curbuf->b_p_iminsert = B_IMODE_IM;
6557 State &= ~LANGMAP;
6558 im_set_active(TRUE);
6559 }
6560 }
6561#endif
6562 set_iminsert_global();
6563 showmode();
6564#ifdef FEAT_GUI
6565 /* may show different cursor shape or color */
6566 if (gui.in_use)
6567 gui_update_cursor(TRUE, FALSE);
6568#endif
6569#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
6570 /* Show/unshow value of 'keymap' in status lines. */
6571 status_redraw_curbuf();
6572#endif
6573}
6574
6575/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576 * Handle ESC in insert mode.
6577 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
6578 * insert.
6579 */
6580 static int
Bram Moolenaar488c6512005-08-11 20:09:58 +00006581ins_esc(count, cmdchar, nomove)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 long *count;
6583 int cmdchar;
Bram Moolenaar488c6512005-08-11 20:09:58 +00006584 int nomove; /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006585{
6586 int temp;
6587 static int disabled_redraw = FALSE;
6588
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006589#ifdef FEAT_SYN_HL
6590 check_spell_redraw();
6591#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006592#if defined(FEAT_HANGULIN)
6593# if defined(ESC_CHG_TO_ENG_MODE)
6594 hangul_input_state_set(0);
6595# endif
6596 if (composing_hangul)
6597 {
6598 push_raw_key(composing_hangul_buffer, 2);
6599 composing_hangul = 0;
6600 }
6601#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006602
6603 temp = curwin->w_cursor.col;
6604 if (disabled_redraw)
6605 {
6606 --RedrawingDisabled;
6607 disabled_redraw = FALSE;
6608 }
6609 if (!arrow_used)
6610 {
6611 /*
6612 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00006613 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
6614 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006615 */
6616 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00006617 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006618
6619 /*
6620 * Repeating insert may take a long time. Check for
6621 * interrupt now and then.
6622 */
6623 if (*count > 0)
6624 {
6625 line_breakcheck();
6626 if (got_int)
6627 *count = 0;
6628 }
6629
6630 if (--*count > 0) /* repeat what was typed */
6631 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00006632 /* Vi repeats the insert without replacing characters. */
6633 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
6634 State &= ~REPLACE_FLAG;
6635
Bram Moolenaar071d4272004-06-13 20:20:40 +00006636 (void)start_redo_ins();
6637 if (cmdchar == 'r' || cmdchar == 'v')
6638 stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
6639 ++RedrawingDisabled;
6640 disabled_redraw = TRUE;
6641 return FALSE; /* repeat the insert */
6642 }
6643 stop_insert(&curwin->w_cursor, TRUE);
6644 undisplay_dollar();
6645 }
6646
6647 /* When an autoindent was removed, curswant stays after the
6648 * indent */
6649 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
6650 curwin->w_set_curswant = TRUE;
6651
6652 /* Remember the last Insert position in the '^ mark. */
6653 if (!cmdmod.keepjumps)
6654 curbuf->b_last_insert = curwin->w_cursor;
6655
6656 /*
6657 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00006658 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006659 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00006660 if (!nomove
6661 && (curwin->w_cursor.col != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662#ifdef FEAT_VIRTUALEDIT
6663 || curwin->w_cursor.coladd > 0
6664#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00006665 )
6666 && (restart_edit == NUL
6667 || (gchar_cursor() == NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006668#ifdef FEAT_VISUAL
Bram Moolenaar488c6512005-08-11 20:09:58 +00006669 && !VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +00006670#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00006671 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006672#ifdef FEAT_RIGHTLEFT
6673 && !revins_on
6674#endif
6675 )
6676 {
6677#ifdef FEAT_VIRTUALEDIT
6678 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
6679 {
6680 oneleft();
6681 if (restart_edit != NUL)
6682 ++curwin->w_cursor.coladd;
6683 }
6684 else
6685#endif
6686 {
6687 --curwin->w_cursor.col;
6688#ifdef FEAT_MBYTE
6689 /* Correct cursor for multi-byte character. */
6690 if (has_mbyte)
6691 mb_adjust_cursor();
6692#endif
6693 }
6694 }
6695
6696#ifdef USE_IM_CONTROL
6697 /* Disable IM to allow typing English directly for Normal mode commands.
6698 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
6699 * well). */
6700 if (!(State & LANGMAP))
6701 im_save_status(&curbuf->b_p_iminsert);
6702 im_set_active(FALSE);
6703#endif
6704
6705 State = NORMAL;
6706 /* need to position cursor again (e.g. when on a TAB ) */
6707 changed_cline_bef_curs();
6708
6709#ifdef FEAT_MOUSE
6710 setmouse();
6711#endif
6712#ifdef CURSOR_SHAPE
6713 ui_cursor_shape(); /* may show different cursor shape */
6714#endif
6715
6716 /*
6717 * When recording or for CTRL-O, need to display the new mode.
6718 * Otherwise remove the mode message.
6719 */
6720 if (Recording || restart_edit != NUL)
6721 showmode();
6722 else if (p_smd)
6723 MSG("");
6724
6725 return TRUE; /* exit Insert mode */
6726}
6727
6728#ifdef FEAT_RIGHTLEFT
6729/*
6730 * Toggle language: hkmap and revins_on.
6731 * Move to end of reverse inserted text.
6732 */
6733 static void
6734ins_ctrl_()
6735{
6736 if (revins_on && revins_chars && revins_scol >= 0)
6737 {
6738 while (gchar_cursor() != NUL && revins_chars--)
6739 ++curwin->w_cursor.col;
6740 }
6741 p_ri = !p_ri;
6742 revins_on = (State == INSERT && p_ri);
6743 if (revins_on)
6744 {
6745 revins_scol = curwin->w_cursor.col;
6746 revins_legal++;
6747 revins_chars = 0;
6748 undisplay_dollar();
6749 }
6750 else
6751 revins_scol = -1;
6752#ifdef FEAT_FKMAP
6753 if (p_altkeymap)
6754 {
6755 /*
6756 * to be consistent also for redo command, using '.'
6757 * set arrow_used to true and stop it - causing to redo
6758 * characters entered in one mode (normal/reverse insert).
6759 */
6760 arrow_used = TRUE;
6761 (void)stop_arrow();
6762 p_fkmap = curwin->w_p_rl ^ p_ri;
6763 if (p_fkmap && p_ri)
6764 State = INSERT;
6765 }
6766 else
6767#endif
6768 p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
6769 showmode();
6770}
6771#endif
6772
6773#ifdef FEAT_VISUAL
6774/*
6775 * If 'keymodel' contains "startsel", may start selection.
6776 * Returns TRUE when a CTRL-O and other keys stuffed.
6777 */
6778 static int
6779ins_start_select(c)
6780 int c;
6781{
6782 if (km_startsel)
6783 switch (c)
6784 {
6785 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006786 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006787 case K_PAGEUP:
6788 case K_KPAGEUP:
6789 case K_PAGEDOWN:
6790 case K_KPAGEDOWN:
6791# ifdef MACOS
6792 case K_LEFT:
6793 case K_RIGHT:
6794 case K_UP:
6795 case K_DOWN:
6796 case K_END:
6797 case K_HOME:
6798# endif
6799 if (!(mod_mask & MOD_MASK_SHIFT))
6800 break;
6801 /* FALLTHROUGH */
6802 case K_S_LEFT:
6803 case K_S_RIGHT:
6804 case K_S_UP:
6805 case K_S_DOWN:
6806 case K_S_END:
6807 case K_S_HOME:
6808 /* Start selection right away, the cursor can move with
6809 * CTRL-O when beyond the end of the line. */
6810 start_selection();
6811
6812 /* Execute the key in (insert) Select mode. */
6813 stuffcharReadbuff(Ctrl_O);
6814 if (mod_mask)
6815 {
6816 char_u buf[4];
6817
6818 buf[0] = K_SPECIAL;
6819 buf[1] = KS_MODIFIER;
6820 buf[2] = mod_mask;
6821 buf[3] = NUL;
6822 stuffReadbuff(buf);
6823 }
6824 stuffcharReadbuff(c);
6825 return TRUE;
6826 }
6827 return FALSE;
6828}
6829#endif
6830
6831/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006832 * <Insert> key in Insert mode: toggle insert/remplace mode.
6833 */
6834 static void
6835ins_insert(replaceState)
6836 int replaceState;
6837{
6838#ifdef FEAT_FKMAP
6839 if (p_fkmap && p_ri)
6840 {
6841 beep_flush();
6842 EMSG(farsi_text_3); /* encoded in Farsi */
6843 return;
6844 }
6845#endif
6846
6847#ifdef FEAT_AUTOCMD
Bram Moolenaar1e015462005-09-25 22:16:38 +00006848# ifdef FEAT_EVAL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006849 set_vim_var_string(VV_INSERTMODE,
6850 (char_u *)((State & REPLACE_FLAG) ? "i" :
6851 replaceState == VREPLACE ? "v" : "r"), 1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006852# endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006853 apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
6854#endif
6855 if (State & REPLACE_FLAG)
6856 State = INSERT | (State & LANGMAP);
6857 else
6858 State = replaceState | (State & LANGMAP);
6859 AppendCharToRedobuff(K_INS);
6860 showmode();
6861#ifdef CURSOR_SHAPE
6862 ui_cursor_shape(); /* may show different cursor shape */
6863#endif
6864}
6865
6866/*
6867 * Pressed CTRL-O in Insert mode.
6868 */
6869 static void
6870ins_ctrl_o()
6871{
6872#ifdef FEAT_VREPLACE
6873 if (State & VREPLACE_FLAG)
6874 restart_edit = 'V';
6875 else
6876#endif
6877 if (State & REPLACE_FLAG)
6878 restart_edit = 'R';
6879 else
6880 restart_edit = 'I';
6881#ifdef FEAT_VIRTUALEDIT
6882 if (virtual_active())
6883 ins_at_eol = FALSE; /* cursor always keeps its column */
6884 else
6885#endif
6886 ins_at_eol = (gchar_cursor() == NUL);
6887}
6888
6889/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006890 * If the cursor is on an indent, ^T/^D insert/delete one
6891 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
6892 * Always round the indent to 'shiftwith', this is compatible
6893 * with vi. But vi only supports ^T and ^D after an
6894 * autoindent, we support it everywhere.
6895 */
6896 static void
6897ins_shift(c, lastc)
6898 int c;
6899 int lastc;
6900{
6901 if (stop_arrow() == FAIL)
6902 return;
6903 AppendCharToRedobuff(c);
6904
6905 /*
6906 * 0^D and ^^D: remove all indent.
6907 */
6908 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
6909 {
6910 --curwin->w_cursor.col;
6911 (void)del_char(FALSE); /* delete the '^' or '0' */
6912 /* In Replace mode, restore the characters that '^' or '0' replaced. */
6913 if (State & REPLACE_FLAG)
6914 replace_pop_ins();
6915 if (lastc == '^')
6916 old_indent = get_indent(); /* remember curr. indent */
6917 change_indent(INDENT_SET, 0, TRUE, 0);
6918 }
6919 else
6920 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
6921
6922 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
6923 did_ai = FALSE;
6924#ifdef FEAT_SMARTINDENT
6925 did_si = FALSE;
6926 can_si = FALSE;
6927 can_si_back = FALSE;
6928#endif
6929#ifdef FEAT_CINDENT
6930 can_cindent = FALSE; /* no cindenting after ^D or ^T */
6931#endif
6932}
6933
6934 static void
6935ins_del()
6936{
6937 int temp;
6938
6939 if (stop_arrow() == FAIL)
6940 return;
6941 if (gchar_cursor() == NUL) /* delete newline */
6942 {
6943 temp = curwin->w_cursor.col;
6944 if (!can_bs(BS_EOL) /* only if "eol" included */
6945 || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
6946 (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
6947 || do_join(FALSE) == FAIL)
6948 vim_beep();
6949 else
6950 curwin->w_cursor.col = temp;
6951 }
6952 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
6953 vim_beep();
6954 did_ai = FALSE;
6955#ifdef FEAT_SMARTINDENT
6956 did_si = FALSE;
6957 can_si = FALSE;
6958 can_si_back = FALSE;
6959#endif
6960 AppendCharToRedobuff(K_DEL);
6961}
6962
6963/*
6964 * Handle Backspace, delete-word and delete-line in Insert mode.
6965 * Return TRUE when backspace was actually used.
6966 */
6967 static int
6968ins_bs(c, mode, inserted_space_p)
6969 int c;
6970 int mode;
6971 int *inserted_space_p;
6972{
6973 linenr_T lnum;
6974 int cc;
6975 int temp = 0; /* init for GCC */
6976 colnr_T mincol;
6977 int did_backspace = FALSE;
6978 int in_indent;
6979 int oldState;
6980#ifdef FEAT_MBYTE
6981 int p1, p2;
6982#endif
6983
6984 /*
6985 * can't delete anything in an empty file
6986 * can't backup past first character in buffer
6987 * can't backup past starting point unless 'backspace' > 1
6988 * can backup to a previous line if 'backspace' == 0
6989 */
6990 if ( bufempty()
6991 || (
6992#ifdef FEAT_RIGHTLEFT
6993 !revins_on &&
6994#endif
6995 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
6996 || (!can_bs(BS_START)
6997 && (arrow_used
6998 || (curwin->w_cursor.lnum == Insstart.lnum
6999 && curwin->w_cursor.col <= Insstart.col)))
7000 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
7001 && curwin->w_cursor.col <= ai_col)
7002 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
7003 {
7004 vim_beep();
7005 return FALSE;
7006 }
7007
7008 if (stop_arrow() == FAIL)
7009 return FALSE;
7010 in_indent = inindent(0);
7011#ifdef FEAT_CINDENT
7012 if (in_indent)
7013 can_cindent = FALSE;
7014#endif
7015#ifdef FEAT_COMMENTS
7016 end_comment_pending = NUL; /* After BS, don't auto-end comment */
7017#endif
7018#ifdef FEAT_RIGHTLEFT
7019 if (revins_on) /* put cursor after last inserted char */
7020 inc_cursor();
7021#endif
7022
7023#ifdef FEAT_VIRTUALEDIT
7024 /* Virtualedit:
7025 * BACKSPACE_CHAR eats a virtual space
7026 * BACKSPACE_WORD eats all coladd
7027 * BACKSPACE_LINE eats all coladd and keeps going
7028 */
7029 if (curwin->w_cursor.coladd > 0)
7030 {
7031 if (mode == BACKSPACE_CHAR)
7032 {
7033 --curwin->w_cursor.coladd;
7034 return TRUE;
7035 }
7036 if (mode == BACKSPACE_WORD)
7037 {
7038 curwin->w_cursor.coladd = 0;
7039 return TRUE;
7040 }
7041 curwin->w_cursor.coladd = 0;
7042 }
7043#endif
7044
7045 /*
7046 * delete newline!
7047 */
7048 if (curwin->w_cursor.col == 0)
7049 {
7050 lnum = Insstart.lnum;
7051 if (curwin->w_cursor.lnum == Insstart.lnum
7052#ifdef FEAT_RIGHTLEFT
7053 || revins_on
7054#endif
7055 )
7056 {
7057 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
7058 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
7059 return FALSE;
7060 --Insstart.lnum;
7061 Insstart.col = MAXCOL;
7062 }
7063 /*
7064 * In replace mode:
7065 * cc < 0: NL was inserted, delete it
7066 * cc >= 0: NL was replaced, put original characters back
7067 */
7068 cc = -1;
7069 if (State & REPLACE_FLAG)
7070 cc = replace_pop(); /* returns -1 if NL was inserted */
7071 /*
7072 * In replace mode, in the line we started replacing, we only move the
7073 * cursor.
7074 */
7075 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
7076 {
7077 dec_cursor();
7078 }
7079 else
7080 {
7081#ifdef FEAT_VREPLACE
7082 if (!(State & VREPLACE_FLAG)
7083 || curwin->w_cursor.lnum > orig_line_count)
7084#endif
7085 {
7086 temp = gchar_cursor(); /* remember current char */
7087 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00007088
7089 /* When "aw" is in 'formatoptions' we must delete the space at
7090 * the end of the line, otherwise the line will be broken
7091 * again when auto-formatting. */
7092 if (has_format_option(FO_AUTO)
7093 && has_format_option(FO_WHITE_PAR))
7094 {
7095 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
7096 TRUE);
7097 int len;
7098
7099 len = STRLEN(ptr);
7100 if (len > 0 && ptr[len - 1] == ' ')
7101 ptr[len - 1] = NUL;
7102 }
7103
Bram Moolenaar071d4272004-06-13 20:20:40 +00007104 (void)do_join(FALSE);
7105 if (temp == NUL && gchar_cursor() != NUL)
7106 inc_cursor();
7107 }
7108#ifdef FEAT_VREPLACE
7109 else
7110 dec_cursor();
7111#endif
7112
7113 /*
7114 * In REPLACE mode we have to put back the text that was replaced
7115 * by the NL. On the replace stack is first a NUL-terminated
7116 * sequence of characters that were deleted and then the
7117 * characters that NL replaced.
7118 */
7119 if (State & REPLACE_FLAG)
7120 {
7121 /*
7122 * Do the next ins_char() in NORMAL state, to
7123 * prevent ins_char() from replacing characters and
7124 * avoiding showmatch().
7125 */
7126 oldState = State;
7127 State = NORMAL;
7128 /*
7129 * restore characters (blanks) deleted after cursor
7130 */
7131 while (cc > 0)
7132 {
7133 temp = curwin->w_cursor.col;
7134#ifdef FEAT_MBYTE
7135 mb_replace_pop_ins(cc);
7136#else
7137 ins_char(cc);
7138#endif
7139 curwin->w_cursor.col = temp;
7140 cc = replace_pop();
7141 }
7142 /* restore the characters that NL replaced */
7143 replace_pop_ins();
7144 State = oldState;
7145 }
7146 }
7147 did_ai = FALSE;
7148 }
7149 else
7150 {
7151 /*
7152 * Delete character(s) before the cursor.
7153 */
7154#ifdef FEAT_RIGHTLEFT
7155 if (revins_on) /* put cursor on last inserted char */
7156 dec_cursor();
7157#endif
7158 mincol = 0;
7159 /* keep indent */
7160 if (mode == BACKSPACE_LINE && curbuf->b_p_ai
7161#ifdef FEAT_RIGHTLEFT
7162 && !revins_on
7163#endif
7164 )
7165 {
7166 temp = curwin->w_cursor.col;
7167 beginline(BL_WHITE);
7168 if (curwin->w_cursor.col < (colnr_T)temp)
7169 mincol = curwin->w_cursor.col;
7170 curwin->w_cursor.col = temp;
7171 }
7172
7173 /*
7174 * Handle deleting one 'shiftwidth' or 'softtabstop'.
7175 */
7176 if ( mode == BACKSPACE_CHAR
7177 && ((p_sta && in_indent)
7178 || (curbuf->b_p_sts
7179 && (*(ml_get_cursor() - 1) == TAB
7180 || (*(ml_get_cursor() - 1) == ' '
7181 && (!*inserted_space_p
7182 || arrow_used))))))
7183 {
7184 int ts;
7185 colnr_T vcol;
7186 colnr_T want_vcol;
7187 int extra = 0;
7188
7189 *inserted_space_p = FALSE;
7190 if (p_sta)
7191 ts = curbuf->b_p_sw;
7192 else
7193 ts = curbuf->b_p_sts;
7194 /* Compute the virtual column where we want to be. Since
7195 * 'showbreak' may get in the way, need to get the last column of
7196 * the previous character. */
7197 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
7198 dec_cursor();
7199 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
7200 inc_cursor();
7201 want_vcol = (want_vcol / ts) * ts;
7202
7203 /* delete characters until we are at or before want_vcol */
7204 while (vcol > want_vcol
7205 && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
7206 {
7207 dec_cursor();
7208 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
7209 if (State & REPLACE_FLAG)
7210 {
7211 /* Don't delete characters before the insert point when in
7212 * Replace mode */
7213 if (curwin->w_cursor.lnum != Insstart.lnum
7214 || curwin->w_cursor.col >= Insstart.col)
7215 {
7216#if 0 /* what was this for? It causes problems when sw != ts. */
7217 if (State == REPLACE && (int)vcol < want_vcol)
7218 {
7219 (void)del_char(FALSE);
7220 extra = 2; /* don't pop too much */
7221 }
7222 else
7223#endif
7224 replace_do_bs();
7225 }
7226 }
7227 else
7228 (void)del_char(FALSE);
7229 }
7230
7231 /* insert extra spaces until we are at want_vcol */
7232 while (vcol < want_vcol)
7233 {
7234 /* Remember the first char we inserted */
7235 if (curwin->w_cursor.lnum == Insstart.lnum
7236 && curwin->w_cursor.col < Insstart.col)
7237 Insstart.col = curwin->w_cursor.col;
7238
7239#ifdef FEAT_VREPLACE
7240 if (State & VREPLACE_FLAG)
7241 ins_char(' ');
7242 else
7243#endif
7244 {
7245 ins_str((char_u *)" ");
7246 if ((State & REPLACE_FLAG) && extra <= 1)
7247 {
7248 if (extra)
7249 replace_push_off(NUL);
7250 else
7251 replace_push(NUL);
7252 }
7253 if (extra == 2)
7254 extra = 1;
7255 }
7256 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
7257 }
7258 }
7259
7260 /*
7261 * Delete upto starting point, start of line or previous word.
7262 */
7263 else do
7264 {
7265#ifdef FEAT_RIGHTLEFT
7266 if (!revins_on) /* put cursor on char to be deleted */
7267#endif
7268 dec_cursor();
7269
7270 /* start of word? */
7271 if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
7272 {
7273 mode = BACKSPACE_WORD_NOT_SPACE;
7274 temp = vim_iswordc(gchar_cursor());
7275 }
7276 /* end of word? */
7277 else if (mode == BACKSPACE_WORD_NOT_SPACE
7278 && (vim_isspace(cc = gchar_cursor())
7279 || vim_iswordc(cc) != temp))
7280 {
7281#ifdef FEAT_RIGHTLEFT
7282 if (!revins_on)
7283#endif
7284 inc_cursor();
7285#ifdef FEAT_RIGHTLEFT
7286 else if (State & REPLACE_FLAG)
7287 dec_cursor();
7288#endif
7289 break;
7290 }
7291 if (State & REPLACE_FLAG)
7292 replace_do_bs();
7293 else
7294 {
7295#ifdef FEAT_MBYTE
7296 if (enc_utf8 && p_deco)
7297 (void)utfc_ptr2char(ml_get_cursor(), &p1, &p2);
7298#endif
7299 (void)del_char(FALSE);
7300#ifdef FEAT_MBYTE
7301 /*
7302 * If p1 or p2 is non-zero, there are combining characters we
7303 * need to take account of. Don't back up before the base
7304 * character.
7305 */
7306 if (enc_utf8 && p_deco && (p1 != NUL || p2 != NUL))
7307 inc_cursor();
7308#endif
7309#ifdef FEAT_RIGHTLEFT
7310 if (revins_chars)
7311 {
7312 revins_chars--;
7313 revins_legal++;
7314 }
7315 if (revins_on && gchar_cursor() == NUL)
7316 break;
7317#endif
7318 }
7319 /* Just a single backspace?: */
7320 if (mode == BACKSPACE_CHAR)
7321 break;
7322 } while (
7323#ifdef FEAT_RIGHTLEFT
7324 revins_on ||
7325#endif
7326 (curwin->w_cursor.col > mincol
7327 && (curwin->w_cursor.lnum != Insstart.lnum
7328 || curwin->w_cursor.col != Insstart.col)));
7329 did_backspace = TRUE;
7330 }
7331#ifdef FEAT_SMARTINDENT
7332 did_si = FALSE;
7333 can_si = FALSE;
7334 can_si_back = FALSE;
7335#endif
7336 if (curwin->w_cursor.col <= 1)
7337 did_ai = FALSE;
7338 /*
7339 * It's a little strange to put backspaces into the redo
7340 * buffer, but it makes auto-indent a lot easier to deal
7341 * with.
7342 */
7343 AppendCharToRedobuff(c);
7344
7345 /* If deleted before the insertion point, adjust it */
7346 if (curwin->w_cursor.lnum == Insstart.lnum
7347 && curwin->w_cursor.col < Insstart.col)
7348 Insstart.col = curwin->w_cursor.col;
7349
7350 /* vi behaviour: the cursor moves backward but the character that
7351 * was there remains visible
7352 * Vim behaviour: the cursor moves backward and the character that
7353 * was there is erased from the screen.
7354 * We can emulate the vi behaviour by pretending there is a dollar
7355 * displayed even when there isn't.
7356 * --pkv Sun Jan 19 01:56:40 EST 2003 */
7357 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == 0)
7358 dollar_vcol = curwin->w_virtcol;
7359
7360 return did_backspace;
7361}
7362
7363#ifdef FEAT_MOUSE
7364 static void
7365ins_mouse(c)
7366 int c;
7367{
7368 pos_T tpos;
7369
7370# ifdef FEAT_GUI
7371 /* When GUI is active, also move/paste when 'mouse' is empty */
7372 if (!gui.in_use)
7373# endif
7374 if (!mouse_has(MOUSE_INSERT))
7375 return;
7376
7377 undisplay_dollar();
7378 tpos = curwin->w_cursor;
7379 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
7380 {
7381 start_arrow(&tpos);
7382# ifdef FEAT_CINDENT
7383 can_cindent = TRUE;
7384# endif
7385 }
7386
7387#ifdef FEAT_WINDOWS
7388 /* redraw status lines (in case another window became active) */
7389 redraw_statuslines();
7390#endif
7391}
7392
7393 static void
7394ins_mousescroll(up)
7395 int up;
7396{
7397 pos_T tpos;
7398# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7399 win_T *old_curwin;
7400# endif
7401
7402 tpos = curwin->w_cursor;
7403
7404# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7405 old_curwin = curwin;
7406
7407 /* Currently the mouse coordinates are only known in the GUI. */
7408 if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
7409 {
7410 int row, col;
7411
7412 row = mouse_row;
7413 col = mouse_col;
7414
7415 /* find the window at the pointer coordinates */
7416 curwin = mouse_find_win(&row, &col);
7417 curbuf = curwin->w_buffer;
7418 }
7419 if (curwin == old_curwin)
7420# endif
7421 undisplay_dollar();
7422
7423 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
7424 scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
7425 else
7426 scroll_redraw(up, 3L);
7427
7428# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7429 curwin->w_redr_status = TRUE;
7430
7431 curwin = old_curwin;
7432 curbuf = curwin->w_buffer;
7433# endif
7434
7435 if (!equalpos(curwin->w_cursor, tpos))
7436 {
7437 start_arrow(&tpos);
7438# ifdef FEAT_CINDENT
7439 can_cindent = TRUE;
7440# endif
7441 }
7442}
7443#endif
7444
7445#ifdef FEAT_GUI
7446 void
7447ins_scroll()
7448{
7449 pos_T tpos;
7450
7451 undisplay_dollar();
7452 tpos = curwin->w_cursor;
7453 if (gui_do_scroll())
7454 {
7455 start_arrow(&tpos);
7456# ifdef FEAT_CINDENT
7457 can_cindent = TRUE;
7458# endif
7459 }
7460}
7461
7462 void
7463ins_horscroll()
7464{
7465 pos_T tpos;
7466
7467 undisplay_dollar();
7468 tpos = curwin->w_cursor;
7469 if (gui_do_horiz_scroll())
7470 {
7471 start_arrow(&tpos);
7472# ifdef FEAT_CINDENT
7473 can_cindent = TRUE;
7474# endif
7475 }
7476}
7477#endif
7478
7479 static void
7480ins_left()
7481{
7482 pos_T tpos;
7483
7484#ifdef FEAT_FOLDING
7485 if ((fdo_flags & FDO_HOR) && KeyTyped)
7486 foldOpenCursor();
7487#endif
7488 undisplay_dollar();
7489 tpos = curwin->w_cursor;
7490 if (oneleft() == OK)
7491 {
7492 start_arrow(&tpos);
7493#ifdef FEAT_RIGHTLEFT
7494 /* If exit reversed string, position is fixed */
7495 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
7496 revins_legal++;
7497 revins_chars++;
7498#endif
7499 }
7500
7501 /*
7502 * if 'whichwrap' set for cursor in insert mode may go to
7503 * previous line
7504 */
7505 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
7506 {
7507 start_arrow(&tpos);
7508 --(curwin->w_cursor.lnum);
7509 coladvance((colnr_T)MAXCOL);
7510 curwin->w_set_curswant = TRUE; /* so we stay at the end */
7511 }
7512 else
7513 vim_beep();
7514}
7515
7516 static void
7517ins_home(c)
7518 int c;
7519{
7520 pos_T tpos;
7521
7522#ifdef FEAT_FOLDING
7523 if ((fdo_flags & FDO_HOR) && KeyTyped)
7524 foldOpenCursor();
7525#endif
7526 undisplay_dollar();
7527 tpos = curwin->w_cursor;
7528 if (c == K_C_HOME)
7529 curwin->w_cursor.lnum = 1;
7530 curwin->w_cursor.col = 0;
7531#ifdef FEAT_VIRTUALEDIT
7532 curwin->w_cursor.coladd = 0;
7533#endif
7534 curwin->w_curswant = 0;
7535 start_arrow(&tpos);
7536}
7537
7538 static void
7539ins_end(c)
7540 int c;
7541{
7542 pos_T tpos;
7543
7544#ifdef FEAT_FOLDING
7545 if ((fdo_flags & FDO_HOR) && KeyTyped)
7546 foldOpenCursor();
7547#endif
7548 undisplay_dollar();
7549 tpos = curwin->w_cursor;
7550 if (c == K_C_END)
7551 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
7552 coladvance((colnr_T)MAXCOL);
7553 curwin->w_curswant = MAXCOL;
7554
7555 start_arrow(&tpos);
7556}
7557
7558 static void
7559ins_s_left()
7560{
7561#ifdef FEAT_FOLDING
7562 if ((fdo_flags & FDO_HOR) && KeyTyped)
7563 foldOpenCursor();
7564#endif
7565 undisplay_dollar();
7566 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
7567 {
7568 start_arrow(&curwin->w_cursor);
7569 (void)bck_word(1L, FALSE, FALSE);
7570 curwin->w_set_curswant = TRUE;
7571 }
7572 else
7573 vim_beep();
7574}
7575
7576 static void
7577ins_right()
7578{
7579#ifdef FEAT_FOLDING
7580 if ((fdo_flags & FDO_HOR) && KeyTyped)
7581 foldOpenCursor();
7582#endif
7583 undisplay_dollar();
7584 if (gchar_cursor() != NUL || virtual_active()
7585 )
7586 {
7587 start_arrow(&curwin->w_cursor);
7588 curwin->w_set_curswant = TRUE;
7589#ifdef FEAT_VIRTUALEDIT
7590 if (virtual_active())
7591 oneright();
7592 else
7593#endif
7594 {
7595#ifdef FEAT_MBYTE
7596 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007597 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00007598 else
7599#endif
7600 ++curwin->w_cursor.col;
7601 }
7602
7603#ifdef FEAT_RIGHTLEFT
7604 revins_legal++;
7605 if (revins_chars)
7606 revins_chars--;
7607#endif
7608 }
7609 /* if 'whichwrap' set for cursor in insert mode, may move the
7610 * cursor to the next line */
7611 else if (vim_strchr(p_ww, ']') != NULL
7612 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
7613 {
7614 start_arrow(&curwin->w_cursor);
7615 curwin->w_set_curswant = TRUE;
7616 ++curwin->w_cursor.lnum;
7617 curwin->w_cursor.col = 0;
7618 }
7619 else
7620 vim_beep();
7621}
7622
7623 static void
7624ins_s_right()
7625{
7626#ifdef FEAT_FOLDING
7627 if ((fdo_flags & FDO_HOR) && KeyTyped)
7628 foldOpenCursor();
7629#endif
7630 undisplay_dollar();
7631 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
7632 || gchar_cursor() != NUL)
7633 {
7634 start_arrow(&curwin->w_cursor);
7635 (void)fwd_word(1L, FALSE, 0);
7636 curwin->w_set_curswant = TRUE;
7637 }
7638 else
7639 vim_beep();
7640}
7641
7642 static void
7643ins_up(startcol)
7644 int startcol; /* when TRUE move to Insstart.col */
7645{
7646 pos_T tpos;
7647 linenr_T old_topline = curwin->w_topline;
7648#ifdef FEAT_DIFF
7649 int old_topfill = curwin->w_topfill;
7650#endif
7651
7652 undisplay_dollar();
7653 tpos = curwin->w_cursor;
7654 if (cursor_up(1L, TRUE) == OK)
7655 {
7656 if (startcol)
7657 coladvance(getvcol_nolist(&Insstart));
7658 if (old_topline != curwin->w_topline
7659#ifdef FEAT_DIFF
7660 || old_topfill != curwin->w_topfill
7661#endif
7662 )
7663 redraw_later(VALID);
7664 start_arrow(&tpos);
7665#ifdef FEAT_CINDENT
7666 can_cindent = TRUE;
7667#endif
7668 }
7669 else
7670 vim_beep();
7671}
7672
7673 static void
7674ins_pageup()
7675{
7676 pos_T tpos;
7677
7678 undisplay_dollar();
7679 tpos = curwin->w_cursor;
7680 if (onepage(BACKWARD, 1L) == OK)
7681 {
7682 start_arrow(&tpos);
7683#ifdef FEAT_CINDENT
7684 can_cindent = TRUE;
7685#endif
7686 }
7687 else
7688 vim_beep();
7689}
7690
7691 static void
7692ins_down(startcol)
7693 int startcol; /* when TRUE move to Insstart.col */
7694{
7695 pos_T tpos;
7696 linenr_T old_topline = curwin->w_topline;
7697#ifdef FEAT_DIFF
7698 int old_topfill = curwin->w_topfill;
7699#endif
7700
7701 undisplay_dollar();
7702 tpos = curwin->w_cursor;
7703 if (cursor_down(1L, TRUE) == OK)
7704 {
7705 if (startcol)
7706 coladvance(getvcol_nolist(&Insstart));
7707 if (old_topline != curwin->w_topline
7708#ifdef FEAT_DIFF
7709 || old_topfill != curwin->w_topfill
7710#endif
7711 )
7712 redraw_later(VALID);
7713 start_arrow(&tpos);
7714#ifdef FEAT_CINDENT
7715 can_cindent = TRUE;
7716#endif
7717 }
7718 else
7719 vim_beep();
7720}
7721
7722 static void
7723ins_pagedown()
7724{
7725 pos_T tpos;
7726
7727 undisplay_dollar();
7728 tpos = curwin->w_cursor;
7729 if (onepage(FORWARD, 1L) == OK)
7730 {
7731 start_arrow(&tpos);
7732#ifdef FEAT_CINDENT
7733 can_cindent = TRUE;
7734#endif
7735 }
7736 else
7737 vim_beep();
7738}
7739
7740#ifdef FEAT_DND
7741 static void
7742ins_drop()
7743{
7744 do_put('~', BACKWARD, 1L, PUT_CURSEND);
7745}
7746#endif
7747
7748/*
7749 * Handle TAB in Insert or Replace mode.
7750 * Return TRUE when the TAB needs to be inserted like a normal character.
7751 */
7752 static int
7753ins_tab()
7754{
7755 int ind;
7756 int i;
7757 int temp;
7758
7759 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
7760 Insstart_blank_vcol = get_nolist_virtcol();
7761 if (echeck_abbr(TAB + ABBR_OFF))
7762 return FALSE;
7763
7764 ind = inindent(0);
7765#ifdef FEAT_CINDENT
7766 if (ind)
7767 can_cindent = FALSE;
7768#endif
7769
7770 /*
7771 * When nothing special, insert TAB like a normal character
7772 */
7773 if (!curbuf->b_p_et
7774 && !(p_sta && ind && curbuf->b_p_ts != curbuf->b_p_sw)
7775 && curbuf->b_p_sts == 0)
7776 return TRUE;
7777
7778 if (stop_arrow() == FAIL)
7779 return TRUE;
7780
7781 did_ai = FALSE;
7782#ifdef FEAT_SMARTINDENT
7783 did_si = FALSE;
7784 can_si = FALSE;
7785 can_si_back = FALSE;
7786#endif
7787 AppendToRedobuff((char_u *)"\t");
7788
7789 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
7790 temp = (int)curbuf->b_p_sw;
7791 else if (curbuf->b_p_sts > 0) /* use 'softtabstop' when set */
7792 temp = (int)curbuf->b_p_sts;
7793 else /* otherwise use 'tabstop' */
7794 temp = (int)curbuf->b_p_ts;
7795 temp -= get_nolist_virtcol() % temp;
7796
7797 /*
7798 * Insert the first space with ins_char(). It will delete one char in
7799 * replace mode. Insert the rest with ins_str(); it will not delete any
7800 * chars. For VREPLACE mode, we use ins_char() for all characters.
7801 */
7802 ins_char(' ');
7803 while (--temp > 0)
7804 {
7805#ifdef FEAT_VREPLACE
7806 if (State & VREPLACE_FLAG)
7807 ins_char(' ');
7808 else
7809#endif
7810 {
7811 ins_str((char_u *)" ");
7812 if (State & REPLACE_FLAG) /* no char replaced */
7813 replace_push(NUL);
7814 }
7815 }
7816
7817 /*
7818 * When 'expandtab' not set: Replace spaces by TABs where possible.
7819 */
7820 if (!curbuf->b_p_et && (curbuf->b_p_sts || (p_sta && ind)))
7821 {
7822 char_u *ptr;
7823#ifdef FEAT_VREPLACE
7824 char_u *saved_line = NULL; /* init for GCC */
7825 pos_T pos;
7826#endif
7827 pos_T fpos;
7828 pos_T *cursor;
7829 colnr_T want_vcol, vcol;
7830 int change_col = -1;
7831 int save_list = curwin->w_p_list;
7832
7833 /*
7834 * Get the current line. For VREPLACE mode, don't make real changes
7835 * yet, just work on a copy of the line.
7836 */
7837#ifdef FEAT_VREPLACE
7838 if (State & VREPLACE_FLAG)
7839 {
7840 pos = curwin->w_cursor;
7841 cursor = &pos;
7842 saved_line = vim_strsave(ml_get_curline());
7843 if (saved_line == NULL)
7844 return FALSE;
7845 ptr = saved_line + pos.col;
7846 }
7847 else
7848#endif
7849 {
7850 ptr = ml_get_cursor();
7851 cursor = &curwin->w_cursor;
7852 }
7853
7854 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
7855 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
7856 curwin->w_p_list = FALSE;
7857
7858 /* Find first white before the cursor */
7859 fpos = curwin->w_cursor;
7860 while (fpos.col > 0 && vim_iswhite(ptr[-1]))
7861 {
7862 --fpos.col;
7863 --ptr;
7864 }
7865
7866 /* In Replace mode, don't change characters before the insert point. */
7867 if ((State & REPLACE_FLAG)
7868 && fpos.lnum == Insstart.lnum
7869 && fpos.col < Insstart.col)
7870 {
7871 ptr += Insstart.col - fpos.col;
7872 fpos.col = Insstart.col;
7873 }
7874
7875 /* compute virtual column numbers of first white and cursor */
7876 getvcol(curwin, &fpos, &vcol, NULL, NULL);
7877 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
7878
7879 /* Use as many TABs as possible. Beware of 'showbreak' and
7880 * 'linebreak' adding extra virtual columns. */
7881 while (vim_iswhite(*ptr))
7882 {
7883 i = lbr_chartabsize((char_u *)"\t", vcol);
7884 if (vcol + i > want_vcol)
7885 break;
7886 if (*ptr != TAB)
7887 {
7888 *ptr = TAB;
7889 if (change_col < 0)
7890 {
7891 change_col = fpos.col; /* Column of first change */
7892 /* May have to adjust Insstart */
7893 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
7894 Insstart.col = fpos.col;
7895 }
7896 }
7897 ++fpos.col;
7898 ++ptr;
7899 vcol += i;
7900 }
7901
7902 if (change_col >= 0)
7903 {
7904 int repl_off = 0;
7905
7906 /* Skip over the spaces we need. */
7907 while (vcol < want_vcol && *ptr == ' ')
7908 {
7909 vcol += lbr_chartabsize(ptr, vcol);
7910 ++ptr;
7911 ++repl_off;
7912 }
7913 if (vcol > want_vcol)
7914 {
7915 /* Must have a char with 'showbreak' just before it. */
7916 --ptr;
7917 --repl_off;
7918 }
7919 fpos.col += repl_off;
7920
7921 /* Delete following spaces. */
7922 i = cursor->col - fpos.col;
7923 if (i > 0)
7924 {
7925 mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
7926 /* correct replace stack. */
7927 if ((State & REPLACE_FLAG)
7928#ifdef FEAT_VREPLACE
7929 && !(State & VREPLACE_FLAG)
7930#endif
7931 )
7932 for (temp = i; --temp >= 0; )
7933 replace_join(repl_off);
7934 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00007935#ifdef FEAT_NETBEANS_INTG
7936 if (usingNetbeans)
7937 {
7938 netbeans_removed(curbuf, fpos.lnum, cursor->col,
7939 (long)(i + 1));
7940 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
7941 (char_u *)"\t", 1);
7942 }
7943#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007944 cursor->col -= i;
7945
7946#ifdef FEAT_VREPLACE
7947 /*
7948 * In VREPLACE mode, we haven't changed anything yet. Do it now by
7949 * backspacing over the changed spacing and then inserting the new
7950 * spacing.
7951 */
7952 if (State & VREPLACE_FLAG)
7953 {
7954 /* Backspace from real cursor to change_col */
7955 backspace_until_column(change_col);
7956
7957 /* Insert each char in saved_line from changed_col to
7958 * ptr-cursor */
7959 ins_bytes_len(saved_line + change_col,
7960 cursor->col - change_col);
7961 }
7962#endif
7963 }
7964
7965#ifdef FEAT_VREPLACE
7966 if (State & VREPLACE_FLAG)
7967 vim_free(saved_line);
7968#endif
7969 curwin->w_p_list = save_list;
7970 }
7971
7972 return FALSE;
7973}
7974
7975/*
7976 * Handle CR or NL in insert mode.
7977 * Return TRUE when out of memory or can't undo.
7978 */
7979 static int
7980ins_eol(c)
7981 int c;
7982{
7983 int i;
7984
7985 if (echeck_abbr(c + ABBR_OFF))
7986 return FALSE;
7987 if (stop_arrow() == FAIL)
7988 return TRUE;
7989 undisplay_dollar();
7990
7991 /*
7992 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
7993 * character under the cursor. Only push a NUL on the replace stack,
7994 * nothing to put back when the NL is deleted.
7995 */
7996 if ((State & REPLACE_FLAG)
7997#ifdef FEAT_VREPLACE
7998 && !(State & VREPLACE_FLAG)
7999#endif
8000 )
8001 replace_push(NUL);
8002
8003 /*
8004 * In VREPLACE mode, a NL replaces the rest of the line, and starts
8005 * replacing the next line, so we push all of the characters left on the
8006 * line onto the replace stack. This is not done here though, it is done
8007 * in open_line().
8008 */
8009
8010#ifdef FEAT_RIGHTLEFT
8011# ifdef FEAT_FKMAP
8012 if (p_altkeymap && p_fkmap)
8013 fkmap(NL);
8014# endif
8015 /* NL in reverse insert will always start in the end of
8016 * current line. */
8017 if (revins_on)
8018 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
8019#endif
8020
8021 AppendToRedobuff(NL_STR);
8022 i = open_line(FORWARD,
8023#ifdef FEAT_COMMENTS
8024 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
8025#endif
8026 0, old_indent);
8027 old_indent = 0;
8028#ifdef FEAT_CINDENT
8029 can_cindent = TRUE;
8030#endif
8031
8032 return (!i);
8033}
8034
8035#ifdef FEAT_DIGRAPHS
8036/*
8037 * Handle digraph in insert mode.
8038 * Returns character still to be inserted, or NUL when nothing remaining to be
8039 * done.
8040 */
8041 static int
8042ins_digraph()
8043{
8044 int c;
8045 int cc;
8046
8047 pc_status = PC_STATUS_UNSET;
8048 if (redrawing() && !char_avail())
8049 {
8050 /* may need to redraw when no more chars available now */
8051 ins_redraw();
8052
8053 edit_putchar('?', TRUE);
8054#ifdef FEAT_CMDL_INFO
8055 add_to_showcmd_c(Ctrl_K);
8056#endif
8057 }
8058
8059#ifdef USE_ON_FLY_SCROLL
8060 dont_scroll = TRUE; /* disallow scrolling here */
8061#endif
8062
8063 /* don't map the digraph chars. This also prevents the
8064 * mode message to be deleted when ESC is hit */
8065 ++no_mapping;
8066 ++allow_keys;
8067 c = safe_vgetc();
8068 --no_mapping;
8069 --allow_keys;
8070 if (IS_SPECIAL(c) || mod_mask) /* special key */
8071 {
8072#ifdef FEAT_CMDL_INFO
8073 clear_showcmd();
8074#endif
8075 insert_special(c, TRUE, FALSE);
8076 return NUL;
8077 }
8078 if (c != ESC)
8079 {
8080 if (redrawing() && !char_avail())
8081 {
8082 /* may need to redraw when no more chars available now */
8083 ins_redraw();
8084
8085 if (char2cells(c) == 1)
8086 {
8087 /* first remove the '?', otherwise it's restored when typing
8088 * an ESC next */
8089 edit_unputchar();
8090 ins_redraw();
8091 edit_putchar(c, TRUE);
8092 }
8093#ifdef FEAT_CMDL_INFO
8094 add_to_showcmd_c(c);
8095#endif
8096 }
8097 ++no_mapping;
8098 ++allow_keys;
8099 cc = safe_vgetc();
8100 --no_mapping;
8101 --allow_keys;
8102 if (cc != ESC)
8103 {
8104 AppendToRedobuff((char_u *)CTRL_V_STR);
8105 c = getdigraph(c, cc, TRUE);
8106#ifdef FEAT_CMDL_INFO
8107 clear_showcmd();
8108#endif
8109 return c;
8110 }
8111 }
8112 edit_unputchar();
8113#ifdef FEAT_CMDL_INFO
8114 clear_showcmd();
8115#endif
8116 return NUL;
8117}
8118#endif
8119
8120/*
8121 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
8122 * Returns the char to be inserted, or NUL if none found.
8123 */
8124 static int
8125ins_copychar(lnum)
8126 linenr_T lnum;
8127{
8128 int c;
8129 int temp;
8130 char_u *ptr, *prev_ptr;
8131
8132 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8133 {
8134 vim_beep();
8135 return NUL;
8136 }
8137
8138 /* try to advance to the cursor column */
8139 temp = 0;
8140 ptr = ml_get(lnum);
8141 prev_ptr = ptr;
8142 validate_virtcol();
8143 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
8144 {
8145 prev_ptr = ptr;
8146 temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
8147 }
8148 if ((colnr_T)temp > curwin->w_virtcol)
8149 ptr = prev_ptr;
8150
8151#ifdef FEAT_MBYTE
8152 c = (*mb_ptr2char)(ptr);
8153#else
8154 c = *ptr;
8155#endif
8156 if (c == NUL)
8157 vim_beep();
8158 return c;
8159}
8160
Bram Moolenaar4be06f92005-07-29 22:36:03 +00008161/*
8162 * CTRL-Y or CTRL-E typed in Insert mode.
8163 */
8164 static int
8165ins_ctrl_ey(tc)
8166 int tc;
8167{
8168 int c = tc;
8169
8170#ifdef FEAT_INS_EXPAND
8171 if (ctrl_x_mode == CTRL_X_SCROLL)
8172 {
8173 if (c == Ctrl_Y)
8174 scrolldown_clamp();
8175 else
8176 scrollup_clamp();
8177 redraw_later(VALID);
8178 }
8179 else
8180#endif
8181 {
8182 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
8183 if (c != NUL)
8184 {
8185 long tw_save;
8186
8187 /* The character must be taken literally, insert like it
8188 * was typed after a CTRL-V, and pretend 'textwidth'
8189 * wasn't set. Digits, 'o' and 'x' are special after a
8190 * CTRL-V, don't use it for these. */
8191 if (c < 256 && !isalnum(c))
8192 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
8193 tw_save = curbuf->b_p_tw;
8194 curbuf->b_p_tw = -1;
8195 insert_special(c, TRUE, FALSE);
8196 curbuf->b_p_tw = tw_save;
8197#ifdef FEAT_RIGHTLEFT
8198 revins_chars++;
8199 revins_legal++;
8200#endif
8201 c = Ctrl_V; /* pretend CTRL-V is last character */
8202 auto_format(FALSE, TRUE);
8203 }
8204 }
8205 return c;
8206}
8207
Bram Moolenaar071d4272004-06-13 20:20:40 +00008208#ifdef FEAT_SMARTINDENT
8209/*
8210 * Try to do some very smart auto-indenting.
8211 * Used when inserting a "normal" character.
8212 */
8213 static void
8214ins_try_si(c)
8215 int c;
8216{
8217 pos_T *pos, old_pos;
8218 char_u *ptr;
8219 int i;
8220 int temp;
8221
8222 /*
8223 * do some very smart indenting when entering '{' or '}'
8224 */
8225 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
8226 {
8227 /*
8228 * for '}' set indent equal to indent of line containing matching '{'
8229 */
8230 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
8231 {
8232 old_pos = curwin->w_cursor;
8233 /*
8234 * If the matching '{' has a ')' immediately before it (ignoring
8235 * white-space), then line up with the start of the line
8236 * containing the matching '(' if there is one. This handles the
8237 * case where an "if (..\n..) {" statement continues over multiple
8238 * lines -- webb
8239 */
8240 ptr = ml_get(pos->lnum);
8241 i = pos->col;
8242 if (i > 0) /* skip blanks before '{' */
8243 while (--i > 0 && vim_iswhite(ptr[i]))
8244 ;
8245 curwin->w_cursor.lnum = pos->lnum;
8246 curwin->w_cursor.col = i;
8247 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
8248 curwin->w_cursor = *pos;
8249 i = get_indent();
8250 curwin->w_cursor = old_pos;
8251#ifdef FEAT_VREPLACE
8252 if (State & VREPLACE_FLAG)
8253 change_indent(INDENT_SET, i, FALSE, NUL);
8254 else
8255#endif
8256 (void)set_indent(i, SIN_CHANGED);
8257 }
8258 else if (curwin->w_cursor.col > 0)
8259 {
8260 /*
8261 * when inserting '{' after "O" reduce indent, but not
8262 * more than indent of previous line
8263 */
8264 temp = TRUE;
8265 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
8266 {
8267 old_pos = curwin->w_cursor;
8268 i = get_indent();
8269 while (curwin->w_cursor.lnum > 1)
8270 {
8271 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
8272
8273 /* ignore empty lines and lines starting with '#'. */
8274 if (*ptr != '#' && *ptr != NUL)
8275 break;
8276 }
8277 if (get_indent() >= i)
8278 temp = FALSE;
8279 curwin->w_cursor = old_pos;
8280 }
8281 if (temp)
8282 shift_line(TRUE, FALSE, 1);
8283 }
8284 }
8285
8286 /*
8287 * set indent of '#' always to 0
8288 */
8289 if (curwin->w_cursor.col > 0 && can_si && c == '#')
8290 {
8291 /* remember current indent for next line */
8292 old_indent = get_indent();
8293 (void)set_indent(0, SIN_CHANGED);
8294 }
8295
8296 /* Adjust ai_col, the char at this position can be deleted. */
8297 if (ai_col > curwin->w_cursor.col)
8298 ai_col = curwin->w_cursor.col;
8299}
8300#endif
8301
8302/*
8303 * Get the value that w_virtcol would have when 'list' is off.
8304 * Unless 'cpo' contains the 'L' flag.
8305 */
8306 static colnr_T
8307get_nolist_virtcol()
8308{
8309 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8310 return getvcol_nolist(&curwin->w_cursor);
8311 validate_virtcol();
8312 return curwin->w_virtcol;
8313}