blob: 96ebe717d14a720c329564d4a2802b4b2e0ca923 [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 Moolenaar4be06f92005-07-29 22:36:03 +000034#define CTRL_X_OCCULT 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 Moolenaar4be06f92005-07-29 22:36:03 +000055 N_(" Occult 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));
112static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int dir, int flags, int thesaurus));
113static void ins_compl_free __ARGS((void));
114static void ins_compl_clear __ARGS((void));
115static void ins_compl_prep __ARGS((int c));
116static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));
117static int ins_compl_get_exp __ARGS((pos_T *ini, int dir));
118static void ins_compl_delete __ARGS((void));
119static void ins_compl_insert __ARGS((void));
120static int ins_compl_next __ARGS((int allow_get_expansion));
121static int ins_complete __ARGS((int c));
122static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
123#endif /* FEAT_INS_EXPAND */
124
125#define BACKSPACE_CHAR 1
126#define BACKSPACE_WORD 2
127#define BACKSPACE_WORD_NOT_SPACE 3
128#define BACKSPACE_LINE 4
129
130static void ins_redraw __ARGS((void));
131static void ins_ctrl_v __ARGS((void));
132static void undisplay_dollar __ARGS((void));
133static void insert_special __ARGS((int, int, int));
134static void check_auto_format __ARGS((int));
135static void redo_literal __ARGS((int c));
136static void start_arrow __ARGS((pos_T *end_insert_pos));
Bram Moolenaar217ad922005-03-20 22:37:15 +0000137#ifdef FEAT_SYN_HL
138static void check_spell_redraw __ARGS((void));
Bram Moolenaar8aff23a2005-08-19 20:40:30 +0000139static void spell_back_to_badword __ARGS((void));
Bram Moolenaar217ad922005-03-20 22:37:15 +0000140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141static void stop_insert __ARGS((pos_T *end_insert_pos, int esc));
142static int echeck_abbr __ARGS((int));
143static void replace_push_off __ARGS((int c));
144static int replace_pop __ARGS((void));
145static void replace_join __ARGS((int off));
146static void replace_pop_ins __ARGS((void));
147#ifdef FEAT_MBYTE
148static void mb_replace_pop_ins __ARGS((int cc));
149#endif
150static void replace_flush __ARGS((void));
151static void replace_do_bs __ARGS((void));
152#ifdef FEAT_CINDENT
153static int cindent_on __ARGS((void));
154#endif
155static void ins_reg __ARGS((void));
156static void ins_ctrl_g __ARGS((void));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000157static void ins_ctrl_hat __ARGS((void));
Bram Moolenaar488c6512005-08-11 20:09:58 +0000158static int ins_esc __ARGS((long *count, int cmdchar, int nomove));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159#ifdef FEAT_RIGHTLEFT
160static void ins_ctrl_ __ARGS((void));
161#endif
162#ifdef FEAT_VISUAL
163static int ins_start_select __ARGS((int c));
164#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000165static void ins_insert __ARGS((int replaceState));
166static void ins_ctrl_o __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167static void ins_shift __ARGS((int c, int lastc));
168static void ins_del __ARGS((void));
169static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
170#ifdef FEAT_MOUSE
171static void ins_mouse __ARGS((int c));
172static void ins_mousescroll __ARGS((int up));
173#endif
174static void ins_left __ARGS((void));
175static void ins_home __ARGS((int c));
176static void ins_end __ARGS((int c));
177static void ins_s_left __ARGS((void));
178static void ins_right __ARGS((void));
179static void ins_s_right __ARGS((void));
180static void ins_up __ARGS((int startcol));
181static void ins_pageup __ARGS((void));
182static void ins_down __ARGS((int startcol));
183static void ins_pagedown __ARGS((void));
184#ifdef FEAT_DND
185static void ins_drop __ARGS((void));
186#endif
187static int ins_tab __ARGS((void));
188static int ins_eol __ARGS((int c));
189#ifdef FEAT_DIGRAPHS
190static int ins_digraph __ARGS((void));
191#endif
192static int ins_copychar __ARGS((linenr_T lnum));
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000193static int ins_ctrl_ey __ARGS((int tc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194#ifdef FEAT_SMARTINDENT
195static void ins_try_si __ARGS((int c));
196#endif
197static colnr_T get_nolist_virtcol __ARGS((void));
198
199static colnr_T Insstart_textlen; /* length of line when insert started */
200static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
201
202static char_u *last_insert = NULL; /* the text of the previous insert,
203 K_SPECIAL and CSI are escaped */
204static int last_insert_skip; /* nr of chars in front of previous insert */
205static int new_insert_skip; /* nr of chars in front of current insert */
206
207#ifdef FEAT_CINDENT
208static int can_cindent; /* may do cindenting on this line */
209#endif
210
211static int old_indent = 0; /* for ^^D command in insert mode */
212
213#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +0000214static int revins_on; /* reverse insert mode on */
215static int revins_chars; /* how much to skip after edit */
216static int revins_legal; /* was the last char 'legal'? */
217static int revins_scol; /* start column of revins session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218#endif
219
220#if defined(FEAT_MBYTE) && defined(MACOS_CLASSIC)
221static short previous_script = smRoman;
222#endif
223
224static int ins_need_undo; /* call u_save() before inserting a
225 char. Set when edit() is called.
226 after that arrow_used is used. */
227
228static int did_add_space = FALSE; /* auto_format() added an extra space
229 under the cursor */
230
231/*
232 * edit(): Start inserting text.
233 *
234 * "cmdchar" can be:
235 * 'i' normal insert command
236 * 'a' normal append command
237 * 'R' replace command
238 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
239 * but still only one <CR> is inserted. The <Esc> is not used for redo.
240 * 'g' "gI" command.
241 * 'V' "gR" command for Virtual Replace mode.
242 * 'v' "gr" command for single character Virtual Replace mode.
243 *
244 * This function is not called recursively. For CTRL-O commands, it returns
245 * and lets the caller handle the Normal-mode command.
246 *
247 * Return TRUE if a CTRL-O command caused the return (insert mode pending).
248 */
249 int
250edit(cmdchar, startln, count)
251 int cmdchar;
252 int startln; /* if set, insert at start of line */
253 long count;
254{
255 int c = 0;
256 char_u *ptr;
257 int lastc;
258 colnr_T mincol;
259 static linenr_T o_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000260 int i;
261 int did_backspace = TRUE; /* previous char was backspace */
262#ifdef FEAT_CINDENT
263 int line_is_white = FALSE; /* line is empty before insert */
264#endif
265 linenr_T old_topline = 0; /* topline before insertion */
266#ifdef FEAT_DIFF
267 int old_topfill = -1;
268#endif
269 int inserted_space = FALSE; /* just inserted a space */
270 int replaceState = REPLACE;
271 int did_restart_edit = restart_edit;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000272 int nomove = FALSE; /* don't move cursor on return */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273
274 /* sleep before redrawing, needed for "CTRL-O :" that results in an
275 * error message */
276 check_for_delay(TRUE);
277
278#ifdef HAVE_SANDBOX
279 /* Don't allow inserting in the sandbox. */
280 if (sandbox != 0)
281 {
282 EMSG(_(e_sandbox));
283 return FALSE;
284 }
285#endif
286
287#ifdef FEAT_INS_EXPAND
288 ins_compl_clear(); /* clear stuff for CTRL-X mode */
289#endif
290
Bram Moolenaar843ee412004-06-30 16:16:41 +0000291#ifdef FEAT_AUTOCMD
292 /*
293 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
294 */
295 if (cmdchar != 'r' && cmdchar != 'v')
296 {
297 if (cmdchar == 'R')
298 ptr = (char_u *)"r";
299 else if (cmdchar == 'V')
300 ptr = (char_u *)"v";
301 else
302 ptr = (char_u *)"i";
303 set_vim_var_string(VV_INSERTMODE, ptr, 1);
304 apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);
305 }
306#endif
307
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308#ifdef FEAT_MOUSE
309 /*
310 * When doing a paste with the middle mouse button, Insstart is set to
311 * where the paste started.
312 */
313 if (where_paste_started.lnum != 0)
314 Insstart = where_paste_started;
315 else
316#endif
317 {
318 Insstart = curwin->w_cursor;
319 if (startln)
320 Insstart.col = 0;
321 }
322 Insstart_textlen = linetabsize(ml_get_curline());
323 Insstart_blank_vcol = MAXCOL;
324 if (!did_ai)
325 ai_col = 0;
326
327 if (cmdchar != NUL && restart_edit == 0)
328 {
329 ResetRedobuff();
330 AppendNumberToRedobuff(count);
331#ifdef FEAT_VREPLACE
332 if (cmdchar == 'V' || cmdchar == 'v')
333 {
334 /* "gR" or "gr" command */
335 AppendCharToRedobuff('g');
336 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
337 }
338 else
339#endif
340 {
341 AppendCharToRedobuff(cmdchar);
342 if (cmdchar == 'g') /* "gI" command */
343 AppendCharToRedobuff('I');
344 else if (cmdchar == 'r') /* "r<CR>" command */
345 count = 1; /* insert only one <CR> */
346 }
347 }
348
349 if (cmdchar == 'R')
350 {
351#ifdef FEAT_FKMAP
352 if (p_fkmap && p_ri)
353 {
354 beep_flush();
355 EMSG(farsi_text_3); /* encoded in Farsi */
356 State = INSERT;
357 }
358 else
359#endif
360 State = REPLACE;
361 }
362#ifdef FEAT_VREPLACE
363 else if (cmdchar == 'V' || cmdchar == 'v')
364 {
365 State = VREPLACE;
366 replaceState = VREPLACE;
367 orig_line_count = curbuf->b_ml.ml_line_count;
368 vr_lines_changed = 1;
369 }
370#endif
371 else
372 State = INSERT;
373
374 stop_insert_mode = FALSE;
375
376 /*
377 * Need to recompute the cursor position, it might move when the cursor is
378 * on a TAB or special character.
379 */
380 curs_columns(TRUE);
381
382 /*
383 * Enable langmap or IME, indicated by 'iminsert'.
384 * Note that IME may enabled/disabled without us noticing here, thus the
385 * 'iminsert' value may not reflect what is actually used. It is updated
386 * when hitting <Esc>.
387 */
388 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
389 State |= LANGMAP;
390#ifdef USE_IM_CONTROL
391 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
392#endif
393
394#if defined(FEAT_MBYTE) && defined(MACOS_CLASSIC)
395 KeyScript(previous_script);
396#endif
397
398#ifdef FEAT_MOUSE
399 setmouse();
400#endif
401#ifdef FEAT_CMDL_INFO
402 clear_showcmd();
403#endif
404#ifdef FEAT_RIGHTLEFT
405 /* there is no reverse replace mode */
406 revins_on = (State == INSERT && p_ri);
407 if (revins_on)
408 undisplay_dollar();
409 revins_chars = 0;
410 revins_legal = 0;
411 revins_scol = -1;
412#endif
413
414 /*
415 * Handle restarting Insert mode.
416 * Don't do this for "CTRL-O ." (repeat an insert): we get here with
417 * restart_edit non-zero, and something in the stuff buffer.
418 */
419 if (restart_edit != 0 && stuff_empty())
420 {
421#ifdef FEAT_MOUSE
422 /*
423 * After a paste we consider text typed to be part of the insert for
424 * the pasted text. You can backspace over the pasted text too.
425 */
426 if (where_paste_started.lnum)
427 arrow_used = FALSE;
428 else
429#endif
430 arrow_used = TRUE;
431 restart_edit = 0;
432
433 /*
434 * If the cursor was after the end-of-line before the CTRL-O and it is
435 * now at the end-of-line, put it after the end-of-line (this is not
436 * correct in very rare cases).
437 * Also do this if curswant is greater than the current virtual
438 * column. Eg after "^O$" or "^O80|".
439 */
440 validate_virtcol();
441 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000442 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 || curwin->w_curswant > curwin->w_virtcol)
444 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
445 {
446 if (ptr[1] == NUL)
447 ++curwin->w_cursor.col;
448#ifdef FEAT_MBYTE
449 else if (has_mbyte)
450 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000451 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452 if (ptr[i] == NUL)
453 curwin->w_cursor.col += i;
454 }
455#endif
456 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000457 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 }
459 else
460 arrow_used = FALSE;
461
462 /* we are in insert mode now, don't need to start it anymore */
463 need_start_insertmode = FALSE;
464
465 /* Need to save the line for undo before inserting the first char. */
466 ins_need_undo = TRUE;
467
468#ifdef FEAT_MOUSE
469 where_paste_started.lnum = 0;
470#endif
471#ifdef FEAT_CINDENT
472 can_cindent = TRUE;
473#endif
474#ifdef FEAT_FOLDING
475 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
476 * restarting. */
477 if (!p_im && did_restart_edit == 0)
478 foldOpenCursor();
479#endif
480
481 /*
482 * If 'showmode' is set, show the current (insert/replace/..) mode.
483 * A warning message for changing a readonly file is given here, before
484 * actually changing anything. It's put after the mode, if any.
485 */
486 i = 0;
487 if (p_smd)
488 i = showmode();
489
490 if (!p_im && did_restart_edit == 0)
491 change_warning(i + 1);
492
493#ifdef CURSOR_SHAPE
494 ui_cursor_shape(); /* may show different cursor shape */
495#endif
496#ifdef FEAT_DIGRAPHS
497 do_digraph(-1); /* clear digraphs */
498#endif
499
500/*
501 * Get the current length of the redo buffer, those characters have to be
502 * skipped if we want to get to the inserted characters.
503 */
504 ptr = get_inserted();
505 if (ptr == NULL)
506 new_insert_skip = 0;
507 else
508 {
509 new_insert_skip = (int)STRLEN(ptr);
510 vim_free(ptr);
511 }
512
513 old_indent = 0;
514
515 /*
516 * Main loop in Insert mode: repeat until Insert mode is left.
517 */
518 for (;;)
519 {
520#ifdef FEAT_RIGHTLEFT
521 if (!revins_legal)
522 revins_scol = -1; /* reset on illegal motions */
523 else
524 revins_legal = 0;
525#endif
526 if (arrow_used) /* don't repeat insert when arrow key used */
527 count = 0;
528
529 if (stop_insert_mode)
530 {
531 /* ":stopinsert" used or 'insertmode' reset */
532 count = 0;
533 goto doESCkey;
534 }
535
536 /* set curwin->w_curswant for next K_DOWN or K_UP */
537 if (!arrow_used)
538 curwin->w_set_curswant = TRUE;
539
540 /* If there is no typeahead may check for timestamps (e.g., for when a
541 * menu invoked a shell command). */
542 if (stuff_empty())
543 {
544 did_check_timestamps = FALSE;
545 if (need_check_timestamps)
546 check_timestamps(FALSE);
547 }
548
549 /*
550 * When emsg() was called msg_scroll will have been set.
551 */
552 msg_scroll = FALSE;
553
554#ifdef FEAT_GUI
555 /* When 'mousefocus' is set a mouse movement may have taken us to
556 * another window. "need_mouse_correct" may then be set because of an
557 * autocommand. */
558 if (need_mouse_correct)
559 gui_mouse_correct();
560#endif
561
562#ifdef FEAT_FOLDING
563 /* Open fold at the cursor line, according to 'foldopen'. */
564 if (fdo_flags & FDO_INSERT)
565 foldOpenCursor();
566 /* Close folds where the cursor isn't, according to 'foldclose' */
567 if (!char_avail())
568 foldCheckClose();
569#endif
570
571 /*
572 * If we inserted a character at the last position of the last line in
573 * the window, scroll the window one line up. This avoids an extra
574 * redraw.
575 * This is detected when the cursor column is smaller after inserting
576 * something.
577 * Don't do this when the topline changed already, it has
578 * already been adjusted (by insertchar() calling open_line())).
579 */
580 if (curbuf->b_mod_set
581 && curwin->w_p_wrap
582 && !did_backspace
583 && curwin->w_topline == old_topline
584#ifdef FEAT_DIFF
585 && curwin->w_topfill == old_topfill
586#endif
587 )
588 {
589 mincol = curwin->w_wcol;
590 validate_cursor_col();
591
592 if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts
593 && curwin->w_wrow == W_WINROW(curwin)
594 + curwin->w_height - 1 - p_so
595 && (curwin->w_cursor.lnum != curwin->w_topline
596#ifdef FEAT_DIFF
597 || curwin->w_topfill > 0
598#endif
599 ))
600 {
601#ifdef FEAT_DIFF
602 if (curwin->w_topfill > 0)
603 --curwin->w_topfill;
604 else
605#endif
606#ifdef FEAT_FOLDING
607 if (hasFolding(curwin->w_topline, NULL, &old_topline))
608 set_topline(curwin, old_topline + 1);
609 else
610#endif
611 set_topline(curwin, curwin->w_topline + 1);
612 }
613 }
614
615 /* May need to adjust w_topline to show the cursor. */
616 update_topline();
617
618 did_backspace = FALSE;
619
620 validate_cursor(); /* may set must_redraw */
621
622 /*
623 * Redraw the display when no characters are waiting.
624 * Also shows mode, ruler and positions cursor.
625 */
626 ins_redraw();
627
628#ifdef FEAT_SCROLLBIND
629 if (curwin->w_p_scb)
630 do_check_scrollbind(TRUE);
631#endif
632
633 update_curswant();
634 old_topline = curwin->w_topline;
635#ifdef FEAT_DIFF
636 old_topfill = curwin->w_topfill;
637#endif
638
639#ifdef USE_ON_FLY_SCROLL
640 dont_scroll = FALSE; /* allow scrolling here */
641#endif
642
643 /*
644 * Get a character for Insert mode.
645 */
646 lastc = c; /* remember previous char for CTRL-D */
647 c = safe_vgetc();
648
649#ifdef FEAT_RIGHTLEFT
650 if (p_hkmap && KeyTyped)
651 c = hkmap(c); /* Hebrew mode mapping */
652#endif
653#ifdef FEAT_FKMAP
654 if (p_fkmap && KeyTyped)
655 c = fkmap(c); /* Farsi mode mapping */
656#endif
657
658#ifdef FEAT_INS_EXPAND
659 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
660 * it does fix up the text when finishing completion. */
Bram Moolenaar572cb562005-08-05 21:35:02 +0000661 if (c != K_IGNORE)
662 ins_compl_prep(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663#endif
664
Bram Moolenaar488c6512005-08-11 20:09:58 +0000665 /* CTRL-\ CTRL-N goes to Normal mode,
666 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
667 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 if (c == Ctrl_BSL)
669 {
670 /* may need to redraw when no more chars available now */
671 ins_redraw();
672 ++no_mapping;
673 ++allow_keys;
674 c = safe_vgetc();
675 --no_mapping;
676 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000677 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000679 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680 vungetc(c);
681 c = Ctrl_BSL;
682 }
683 else if (c == Ctrl_G && p_im)
684 continue;
685 else
686 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000687 if (c == Ctrl_O)
688 {
689 ins_ctrl_o();
690 ins_at_eol = FALSE; /* cursor keeps its column */
691 nomove = TRUE;
692 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693 count = 0;
694 goto doESCkey;
695 }
696 }
697
698#ifdef FEAT_DIGRAPHS
699 c = do_digraph(c);
700#endif
701
702#ifdef FEAT_INS_EXPAND
703 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
704 goto docomplete;
705#endif
706 if (c == Ctrl_V || c == Ctrl_Q)
707 {
708 ins_ctrl_v();
709 c = Ctrl_V; /* pretend CTRL-V is last typed character */
710 continue;
711 }
712
713#ifdef FEAT_CINDENT
714 if (cindent_on()
715# ifdef FEAT_INS_EXPAND
716 && ctrl_x_mode == 0
717# endif
718 )
719 {
720 /* A key name preceded by a bang means this key is not to be
721 * inserted. Skip ahead to the re-indenting below.
722 * A key name preceded by a star means that indenting has to be
723 * done before inserting the key. */
724 line_is_white = inindent(0);
725 if (in_cinkeys(c, '!', line_is_white))
726 goto force_cindent;
727 if (can_cindent && in_cinkeys(c, '*', line_is_white)
728 && stop_arrow() == OK)
729 do_c_expr_indent();
730 }
731#endif
732
733#ifdef FEAT_RIGHTLEFT
734 if (curwin->w_p_rl)
735 switch (c)
736 {
737 case K_LEFT: c = K_RIGHT; break;
738 case K_S_LEFT: c = K_S_RIGHT; break;
739 case K_C_LEFT: c = K_C_RIGHT; break;
740 case K_RIGHT: c = K_LEFT; break;
741 case K_S_RIGHT: c = K_S_LEFT; break;
742 case K_C_RIGHT: c = K_C_LEFT; break;
743 }
744#endif
745
746#ifdef FEAT_VISUAL
747 /*
748 * If 'keymodel' contains "startsel", may start selection. If it
749 * does, a CTRL-O and c will be stuffed, we need to get these
750 * characters.
751 */
752 if (ins_start_select(c))
753 continue;
754#endif
755
756 /*
757 * The big switch to handle a character in insert mode.
758 */
759 switch (c)
760 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000761 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 if (echeck_abbr(ESC + ABBR_OFF))
763 break;
764 /*FALLTHROUGH*/
765
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000766 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767#ifdef FEAT_CMDWIN
768 if (c == Ctrl_C && cmdwin_type != 0)
769 {
770 /* Close the cmdline window. */
771 cmdwin_result = K_IGNORE;
772 got_int = FALSE; /* don't stop executing autocommands et al. */
773 goto doESCkey;
774 }
775#endif
776
777#ifdef UNIX
778do_intr:
779#endif
780 /* when 'insertmode' set, and not halfway a mapping, don't leave
781 * Insert mode */
782 if (goto_im())
783 {
784 if (got_int)
785 {
786 (void)vgetc(); /* flush all buffers */
787 got_int = FALSE;
788 }
789 else
790 vim_beep();
791 break;
792 }
793doESCkey:
794 /*
795 * This is the ONLY return from edit()!
796 */
797 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
798 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000799 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 o_lnum = curwin->w_cursor.lnum;
801
Bram Moolenaar488c6512005-08-11 20:09:58 +0000802 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000803 {
804#ifdef FEAT_AUTOCMD
805 if (cmdchar != 'r' && cmdchar != 'v')
806 apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL,
807 FALSE, curbuf);
808#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000810 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 continue;
812
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000813 case Ctrl_Z: /* suspend when 'insertmode' set */
814 if (!p_im)
815 goto normalchar; /* insert CTRL-Z as normal char */
816 stuffReadbuff((char_u *)":st\r");
817 c = Ctrl_O;
818 /*FALLTHROUGH*/
819
820 case Ctrl_O: /* execute one command */
821#ifdef FEAT_INS_EXPAND
822 if (ctrl_x_mode == CTRL_X_OCCULT)
823 goto docomplete;
824#endif
825 if (echeck_abbr(Ctrl_O + ABBR_OFF))
826 break;
827 ins_ctrl_o();
828 count = 0;
829 goto doESCkey;
830
Bram Moolenaar572cb562005-08-05 21:35:02 +0000831 case K_INS: /* toggle insert/replace mode */
832 case K_KINS:
833 ins_insert(replaceState);
834 break;
835
836 case K_SELECT: /* end of Select mode mapping - ignore */
837 break;
838
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000839#ifdef FEAT_SNIFF
840 case K_SNIFF: /* Sniff command received */
841 stuffcharReadbuff(K_SNIFF);
842 goto doESCkey;
843#endif
844
845 case K_HELP: /* Help key works like <ESC> <Help> */
846 case K_F1:
847 case K_XF1:
848 stuffcharReadbuff(K_HELP);
849 if (p_im)
850 need_start_insertmode = TRUE;
851 goto doESCkey;
852
853#ifdef FEAT_NETBEANS_INTG
854 case K_F21: /* NetBeans command */
855 ++no_mapping; /* don't map the next key hits */
856 i = safe_vgetc();
857 --no_mapping;
858 netbeans_keycommand(i);
859 break;
860#endif
861
862 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 case NUL:
864 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000865 /* For ^@ the trailing ESC will end the insert, unless there is an
866 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
868 && c != Ctrl_A && !p_im)
869 goto doESCkey; /* quit insert mode */
870 inserted_space = FALSE;
871 break;
872
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000873 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 ins_reg();
875 auto_format(FALSE, TRUE);
876 inserted_space = FALSE;
877 break;
878
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000879 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 ins_ctrl_g();
881 break;
882
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000883 case Ctrl_HAT: /* switch input mode and/or langmap */
884 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 break;
886
887#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000888 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 if (!p_ari)
890 goto normalchar;
891 ins_ctrl_();
892 break;
893#endif
894
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000895 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
897 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
898 goto docomplete;
899#endif
900 /* FALLTHROUGH */
901
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000902 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903# ifdef FEAT_INS_EXPAND
904 if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
905 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000906 if (has_compl_option(FALSE))
907 goto docomplete;
908 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 }
910# endif
911 ins_shift(c, lastc);
912 auto_format(FALSE, TRUE);
913 inserted_space = FALSE;
914 break;
915
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000916 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 case K_KDEL:
918 ins_del();
919 auto_format(FALSE, TRUE);
920 break;
921
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000922 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923 case Ctrl_H:
924 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
925 auto_format(FALSE, TRUE);
926 break;
927
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000928 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000929 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
930 auto_format(FALSE, TRUE);
931 break;
932
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000933 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000934# ifdef FEAT_COMPL_FUNC
935 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000936 if (ctrl_x_mode == CTRL_X_FUNCTION)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000937 goto docomplete;
938# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000939 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
940 auto_format(FALSE, TRUE);
941 inserted_space = FALSE;
942 break;
943
944#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000945 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 case K_LEFTMOUSE_NM:
947 case K_LEFTDRAG:
948 case K_LEFTRELEASE:
949 case K_LEFTRELEASE_NM:
950 case K_MIDDLEMOUSE:
951 case K_MIDDLEDRAG:
952 case K_MIDDLERELEASE:
953 case K_RIGHTMOUSE:
954 case K_RIGHTDRAG:
955 case K_RIGHTRELEASE:
956 case K_X1MOUSE:
957 case K_X1DRAG:
958 case K_X1RELEASE:
959 case K_X2MOUSE:
960 case K_X2DRAG:
961 case K_X2RELEASE:
962 ins_mouse(c);
963 break;
964
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000965 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 ins_mousescroll(FALSE);
967 break;
968
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000969 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970 ins_mousescroll(TRUE);
971 break;
972#endif
973
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000974 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 break;
976
977#ifdef FEAT_GUI
978 case K_VER_SCROLLBAR:
979 ins_scroll();
980 break;
981
982 case K_HOR_SCROLLBAR:
983 ins_horscroll();
984 break;
985#endif
986
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000987 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989 case K_S_HOME:
990 case K_C_HOME:
991 ins_home(c);
992 break;
993
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000994 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 case K_S_END:
997 case K_C_END:
998 ins_end(c);
999 break;
1000
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001001 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001002 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1003 ins_s_left();
1004 else
1005 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 break;
1007
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001008 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 case K_C_LEFT:
1010 ins_s_left();
1011 break;
1012
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001013 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001014 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1015 ins_s_right();
1016 else
1017 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 break;
1019
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001020 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021 case K_C_RIGHT:
1022 ins_s_right();
1023 break;
1024
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001025 case K_UP: /* <Up> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001026 if (mod_mask & MOD_MASK_SHIFT)
1027 ins_pageup();
1028 else
1029 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 break;
1031
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001032 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 case K_PAGEUP:
1034 case K_KPAGEUP:
1035 ins_pageup();
1036 break;
1037
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001038 case K_DOWN: /* <Down> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001039 if (mod_mask & MOD_MASK_SHIFT)
1040 ins_pagedown();
1041 else
1042 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 break;
1044
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001045 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 case K_PAGEDOWN:
1047 case K_KPAGEDOWN:
1048 ins_pagedown();
1049 break;
1050
1051#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001052 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 ins_drop();
1054 break;
1055#endif
1056
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001057 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 c = TAB;
1059 /* FALLTHROUGH */
1060
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001061 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
1063 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
1064 goto docomplete;
1065#endif
1066 inserted_space = FALSE;
1067 if (ins_tab())
1068 goto normalchar; /* insert TAB as a normal char */
1069 auto_format(FALSE, TRUE);
1070 break;
1071
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001072 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073 c = CAR;
1074 /* FALLTHROUGH */
1075 case CAR:
1076 case NL:
1077#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
1078 /* In a quickfix window a <CR> jumps to the error under the
1079 * cursor. */
1080 if (bt_quickfix(curbuf) && c == CAR)
1081 {
1082 do_cmdline_cmd((char_u *)".cc");
1083 break;
1084 }
1085#endif
1086#ifdef FEAT_CMDWIN
1087 if (cmdwin_type != 0)
1088 {
1089 /* Execute the command in the cmdline window. */
1090 cmdwin_result = CAR;
1091 goto doESCkey;
1092 }
1093#endif
1094 if (ins_eol(c) && !p_im)
1095 goto doESCkey; /* out of memory */
1096 auto_format(FALSE, FALSE);
1097 inserted_space = FALSE;
1098 break;
1099
1100#if defined(FEAT_DIGRAPHS) || defined (FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001101 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102# ifdef FEAT_INS_EXPAND
1103 if (ctrl_x_mode == CTRL_X_DICTIONARY)
1104 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001105 if (has_compl_option(TRUE))
1106 goto docomplete;
1107 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001108 }
1109# endif
1110# ifdef FEAT_DIGRAPHS
1111 c = ins_digraph();
1112 if (c == NUL)
1113 break;
1114# endif
1115 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001116#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117
1118#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001119 case Ctrl_X: /* Enter CTRL-X mode */
1120 ins_ctrl_x();
1121 break;
1122
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001123 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 if (ctrl_x_mode != CTRL_X_TAGS)
1125 goto normalchar;
1126 goto docomplete;
1127
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001128 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 if (ctrl_x_mode != CTRL_X_FILES)
1130 goto normalchar;
1131 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001132
1133 case 's': /* Spelling completion after ^X */
1134 case Ctrl_S:
1135 if (ctrl_x_mode != CTRL_X_SPELL)
1136 goto normalchar;
1137 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001138#endif
1139
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001140 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141#ifdef FEAT_INS_EXPAND
1142 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
1143#endif
1144 {
1145 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1146 if (p_im)
1147 {
1148 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1149 break;
1150 goto doESCkey;
1151 }
1152 goto normalchar;
1153 }
1154#ifdef FEAT_INS_EXPAND
1155 /* FALLTHROUGH */
1156
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001157 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 case Ctrl_N:
1159 /* if 'complete' is empty then plain ^P is no longer special,
1160 * but it is under other ^X modes */
1161 if (*curbuf->b_p_cpt == NUL
1162 && ctrl_x_mode != 0
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001163 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 goto normalchar;
1165
1166docomplete:
1167 if (ins_complete(c) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001168 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169 break;
1170#endif /* FEAT_INS_EXPAND */
1171
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001172 case Ctrl_Y: /* copy from previous line or scroll down */
1173 case Ctrl_E: /* copy from next line or scroll up */
1174 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 break;
1176
1177 default:
1178#ifdef UNIX
1179 if (c == intr_char) /* special interrupt char */
1180 goto do_intr;
1181#endif
1182
1183 /*
1184 * Insert a nomal character.
1185 */
1186normalchar:
1187#ifdef FEAT_SMARTINDENT
1188 /* Try to perform smart-indenting. */
1189 ins_try_si(c);
1190#endif
1191
1192 if (c == ' ')
1193 {
1194 inserted_space = TRUE;
1195#ifdef FEAT_CINDENT
1196 if (inindent(0))
1197 can_cindent = FALSE;
1198#endif
1199 if (Insstart_blank_vcol == MAXCOL
1200 && curwin->w_cursor.lnum == Insstart.lnum)
1201 Insstart_blank_vcol = get_nolist_virtcol();
1202 }
1203
1204 if (vim_iswordc(c) || !echeck_abbr(
1205#ifdef FEAT_MBYTE
1206 /* Add ABBR_OFF for characters above 0x100, this is
1207 * what check_abbr() expects. */
1208 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1209#endif
1210 c))
1211 {
1212 insert_special(c, FALSE, FALSE);
1213#ifdef FEAT_RIGHTLEFT
1214 revins_legal++;
1215 revins_chars++;
1216#endif
1217 }
1218
1219 auto_format(FALSE, TRUE);
1220
1221#ifdef FEAT_FOLDING
1222 /* When inserting a character the cursor line must never be in a
1223 * closed fold. */
1224 foldOpenCursor();
1225#endif
1226 break;
1227 } /* end of switch (c) */
1228
1229 /* If the cursor was moved we didn't just insert a space */
1230 if (arrow_used)
1231 inserted_space = FALSE;
1232
1233#ifdef FEAT_CINDENT
1234 if (can_cindent && cindent_on()
1235# ifdef FEAT_INS_EXPAND
1236 && ctrl_x_mode == 0
1237# endif
1238 )
1239 {
1240force_cindent:
1241 /*
1242 * Indent now if a key was typed that is in 'cinkeys'.
1243 */
1244 if (in_cinkeys(c, ' ', line_is_white))
1245 {
1246 if (stop_arrow() == OK)
1247 /* re-indent the current line */
1248 do_c_expr_indent();
1249 }
1250 }
1251#endif /* FEAT_CINDENT */
1252
1253 } /* for (;;) */
1254 /* NOTREACHED */
1255}
1256
1257/*
1258 * Redraw for Insert mode.
1259 * This is postponed until getting the next character to make '$' in the 'cpo'
1260 * option work correctly.
1261 * Only redraw when there are no characters available. This speeds up
1262 * inserting sequences of characters (e.g., for CTRL-R).
1263 */
1264 static void
1265ins_redraw()
1266{
1267 if (!char_avail())
1268 {
1269 if (must_redraw)
1270 update_screen(0);
1271 else if (clear_cmdline || redraw_cmdline)
1272 showmode(); /* clear cmdline and show mode */
1273 showruler(FALSE);
1274 setcursor();
1275 emsg_on_display = FALSE; /* may remove error message now */
1276 }
1277}
1278
1279/*
1280 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1281 */
1282 static void
1283ins_ctrl_v()
1284{
1285 int c;
1286
1287 /* may need to redraw when no more chars available now */
1288 ins_redraw();
1289
1290 if (redrawing() && !char_avail())
1291 edit_putchar('^', TRUE);
1292 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1293
1294#ifdef FEAT_CMDL_INFO
1295 add_to_showcmd_c(Ctrl_V);
1296#endif
1297
1298 c = get_literal();
1299#ifdef FEAT_CMDL_INFO
1300 clear_showcmd();
1301#endif
1302 insert_special(c, FALSE, TRUE);
1303#ifdef FEAT_RIGHTLEFT
1304 revins_chars++;
1305 revins_legal++;
1306#endif
1307}
1308
1309/*
1310 * Put a character directly onto the screen. It's not stored in a buffer.
1311 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1312 */
1313static int pc_status;
1314#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1315#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1316#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1317#define PC_STATUS_SET 3 /* pc_bytes was filled */
1318#ifdef FEAT_MBYTE
1319static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1320#else
1321static char_u pc_bytes[2]; /* saved bytes */
1322#endif
1323static int pc_attr;
1324static int pc_row;
1325static int pc_col;
1326
1327 void
1328edit_putchar(c, highlight)
1329 int c;
1330 int highlight;
1331{
1332 int attr;
1333
1334 if (ScreenLines != NULL)
1335 {
1336 update_topline(); /* just in case w_topline isn't valid */
1337 validate_cursor();
1338 if (highlight)
1339 attr = hl_attr(HLF_8);
1340 else
1341 attr = 0;
1342 pc_row = W_WINROW(curwin) + curwin->w_wrow;
1343 pc_col = W_WINCOL(curwin);
1344#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1345 pc_status = PC_STATUS_UNSET;
1346#endif
1347#ifdef FEAT_RIGHTLEFT
1348 if (curwin->w_p_rl)
1349 {
1350 pc_col += W_WIDTH(curwin) - 1 - curwin->w_wcol;
1351# ifdef FEAT_MBYTE
1352 if (has_mbyte)
1353 {
1354 int fix_col = mb_fix_col(pc_col, pc_row);
1355
1356 if (fix_col != pc_col)
1357 {
1358 screen_putchar(' ', pc_row, fix_col, attr);
1359 --curwin->w_wcol;
1360 pc_status = PC_STATUS_RIGHT;
1361 }
1362 }
1363# endif
1364 }
1365 else
1366#endif
1367 {
1368 pc_col += curwin->w_wcol;
1369#ifdef FEAT_MBYTE
1370 if (mb_lefthalve(pc_row, pc_col))
1371 pc_status = PC_STATUS_LEFT;
1372#endif
1373 }
1374
1375 /* save the character to be able to put it back */
1376#if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1377 if (pc_status == PC_STATUS_UNSET)
1378#endif
1379 {
1380 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1381 pc_status = PC_STATUS_SET;
1382 }
1383 screen_putchar(c, pc_row, pc_col, attr);
1384 }
1385}
1386
1387/*
1388 * Undo the previous edit_putchar().
1389 */
1390 void
1391edit_unputchar()
1392{
1393 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1394 {
1395#if defined(FEAT_MBYTE)
1396 if (pc_status == PC_STATUS_RIGHT)
1397 ++curwin->w_wcol;
1398 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
1399 redrawWinline(curwin->w_cursor.lnum, FALSE);
1400 else
1401#endif
1402 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1403 }
1404}
1405
1406/*
1407 * Called when p_dollar is set: display a '$' at the end of the changed text
1408 * Only works when cursor is in the line that changes.
1409 */
1410 void
1411display_dollar(col)
1412 colnr_T col;
1413{
1414 colnr_T save_col;
1415
1416 if (!redrawing())
1417 return;
1418
1419 cursor_off();
1420 save_col = curwin->w_cursor.col;
1421 curwin->w_cursor.col = col;
1422#ifdef FEAT_MBYTE
1423 if (has_mbyte)
1424 {
1425 char_u *p;
1426
1427 /* If on the last byte of a multi-byte move to the first byte. */
1428 p = ml_get_curline();
1429 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1430 }
1431#endif
1432 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
1433 if (curwin->w_wcol < W_WIDTH(curwin))
1434 {
1435 edit_putchar('$', FALSE);
1436 dollar_vcol = curwin->w_virtcol;
1437 }
1438 curwin->w_cursor.col = save_col;
1439}
1440
1441/*
1442 * Call this function before moving the cursor from the normal insert position
1443 * in insert mode.
1444 */
1445 static void
1446undisplay_dollar()
1447{
1448 if (dollar_vcol)
1449 {
1450 dollar_vcol = 0;
1451 redrawWinline(curwin->w_cursor.lnum, FALSE);
1452 }
1453}
1454
1455/*
1456 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1457 * Keep the cursor on the same character.
1458 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1459 * type == INDENT_DEC decrease indent (for CTRL-D)
1460 * type == INDENT_SET set indent to "amount"
1461 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1462 */
1463 void
1464change_indent(type, amount, round, replaced)
1465 int type;
1466 int amount;
1467 int round;
1468 int replaced; /* replaced character, put on replace stack */
1469{
1470 int vcol;
1471 int last_vcol;
1472 int insstart_less; /* reduction for Insstart.col */
1473 int new_cursor_col;
1474 int i;
1475 char_u *ptr;
1476 int save_p_list;
1477 int start_col;
1478 colnr_T vc;
1479#ifdef FEAT_VREPLACE
1480 colnr_T orig_col = 0; /* init for GCC */
1481 char_u *new_line, *orig_line = NULL; /* init for GCC */
1482
1483 /* VREPLACE mode needs to know what the line was like before changing */
1484 if (State & VREPLACE_FLAG)
1485 {
1486 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1487 orig_col = curwin->w_cursor.col;
1488 }
1489#endif
1490
1491 /* for the following tricks we don't want list mode */
1492 save_p_list = curwin->w_p_list;
1493 curwin->w_p_list = FALSE;
1494 vc = getvcol_nolist(&curwin->w_cursor);
1495 vcol = vc;
1496
1497 /*
1498 * For Replace mode we need to fix the replace stack later, which is only
1499 * possible when the cursor is in the indent. Remember the number of
1500 * characters before the cursor if it's possible.
1501 */
1502 start_col = curwin->w_cursor.col;
1503
1504 /* determine offset from first non-blank */
1505 new_cursor_col = curwin->w_cursor.col;
1506 beginline(BL_WHITE);
1507 new_cursor_col -= curwin->w_cursor.col;
1508
1509 insstart_less = curwin->w_cursor.col;
1510
1511 /*
1512 * If the cursor is in the indent, compute how many screen columns the
1513 * cursor is to the left of the first non-blank.
1514 */
1515 if (new_cursor_col < 0)
1516 vcol = get_indent() - vcol;
1517
1518 if (new_cursor_col > 0) /* can't fix replace stack */
1519 start_col = -1;
1520
1521 /*
1522 * Set the new indent. The cursor will be put on the first non-blank.
1523 */
1524 if (type == INDENT_SET)
1525 (void)set_indent(amount, SIN_CHANGED);
1526 else
1527 {
1528#ifdef FEAT_VREPLACE
1529 int save_State = State;
1530
1531 /* Avoid being called recursively. */
1532 if (State & VREPLACE_FLAG)
1533 State = INSERT;
1534#endif
1535 shift_line(type == INDENT_DEC, round, 1);
1536#ifdef FEAT_VREPLACE
1537 State = save_State;
1538#endif
1539 }
1540 insstart_less -= curwin->w_cursor.col;
1541
1542 /*
1543 * Try to put cursor on same character.
1544 * If the cursor is at or after the first non-blank in the line,
1545 * compute the cursor column relative to the column of the first
1546 * non-blank character.
1547 * If we are not in insert mode, leave the cursor on the first non-blank.
1548 * If the cursor is before the first non-blank, position it relative
1549 * to the first non-blank, counted in screen columns.
1550 */
1551 if (new_cursor_col >= 0)
1552 {
1553 /*
1554 * When changing the indent while the cursor is touching it, reset
1555 * Insstart_col to 0.
1556 */
1557 if (new_cursor_col == 0)
1558 insstart_less = MAXCOL;
1559 new_cursor_col += curwin->w_cursor.col;
1560 }
1561 else if (!(State & INSERT))
1562 new_cursor_col = curwin->w_cursor.col;
1563 else
1564 {
1565 /*
1566 * Compute the screen column where the cursor should be.
1567 */
1568 vcol = get_indent() - vcol;
1569 curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
1570
1571 /*
1572 * Advance the cursor until we reach the right screen column.
1573 */
1574 vcol = last_vcol = 0;
1575 new_cursor_col = -1;
1576 ptr = ml_get_curline();
1577 while (vcol <= (int)curwin->w_virtcol)
1578 {
1579 last_vcol = vcol;
1580#ifdef FEAT_MBYTE
1581 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001582 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 else
1584#endif
1585 ++new_cursor_col;
1586 vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol);
1587 }
1588 vcol = last_vcol;
1589
1590 /*
1591 * May need to insert spaces to be able to position the cursor on
1592 * the right screen column.
1593 */
1594 if (vcol != (int)curwin->w_virtcol)
1595 {
1596 curwin->w_cursor.col = new_cursor_col;
1597 i = (int)curwin->w_virtcol - vcol;
1598 ptr = alloc(i + 1);
1599 if (ptr != NULL)
1600 {
1601 new_cursor_col += i;
1602 ptr[i] = NUL;
1603 while (--i >= 0)
1604 ptr[i] = ' ';
1605 ins_str(ptr);
1606 vim_free(ptr);
1607 }
1608 }
1609
1610 /*
1611 * When changing the indent while the cursor is in it, reset
1612 * Insstart_col to 0.
1613 */
1614 insstart_less = MAXCOL;
1615 }
1616
1617 curwin->w_p_list = save_p_list;
1618
1619 if (new_cursor_col <= 0)
1620 curwin->w_cursor.col = 0;
1621 else
1622 curwin->w_cursor.col = new_cursor_col;
1623 curwin->w_set_curswant = TRUE;
1624 changed_cline_bef_curs();
1625
1626 /*
1627 * May have to adjust the start of the insert.
1628 */
1629 if (State & INSERT)
1630 {
1631 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1632 {
1633 if ((int)Insstart.col <= insstart_less)
1634 Insstart.col = 0;
1635 else
1636 Insstart.col -= insstart_less;
1637 }
1638 if ((int)ai_col <= insstart_less)
1639 ai_col = 0;
1640 else
1641 ai_col -= insstart_less;
1642 }
1643
1644 /*
1645 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1646 * If the number of characters before the cursor decreased, need to pop a
1647 * few characters from the replace stack.
1648 * If the number of characters before the cursor increased, need to push a
1649 * few NULs onto the replace stack.
1650 */
1651 if (REPLACE_NORMAL(State) && start_col >= 0)
1652 {
1653 while (start_col > (int)curwin->w_cursor.col)
1654 {
1655 replace_join(0); /* remove a NUL from the replace stack */
1656 --start_col;
1657 }
1658 while (start_col < (int)curwin->w_cursor.col || replaced)
1659 {
1660 replace_push(NUL);
1661 if (replaced)
1662 {
1663 replace_push(replaced);
1664 replaced = NUL;
1665 }
1666 ++start_col;
1667 }
1668 }
1669
1670#ifdef FEAT_VREPLACE
1671 /*
1672 * For VREPLACE mode, we also have to fix the replace stack. In this case
1673 * it is always possible because we backspace over the whole line and then
1674 * put it back again the way we wanted it.
1675 */
1676 if (State & VREPLACE_FLAG)
1677 {
1678 /* If orig_line didn't allocate, just return. At least we did the job,
1679 * even if you can't backspace. */
1680 if (orig_line == NULL)
1681 return;
1682
1683 /* Save new line */
1684 new_line = vim_strsave(ml_get_curline());
1685 if (new_line == NULL)
1686 return;
1687
1688 /* We only put back the new line up to the cursor */
1689 new_line[curwin->w_cursor.col] = NUL;
1690
1691 /* Put back original line */
1692 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1693 curwin->w_cursor.col = orig_col;
1694
1695 /* Backspace from cursor to start of line */
1696 backspace_until_column(0);
1697
1698 /* Insert new stuff into line again */
1699 ins_bytes(new_line);
1700
1701 vim_free(new_line);
1702 }
1703#endif
1704}
1705
1706/*
1707 * Truncate the space at the end of a line. This is to be used only in an
1708 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1709 * modes.
1710 */
1711 void
1712truncate_spaces(line)
1713 char_u *line;
1714{
1715 int i;
1716
1717 /* find start of trailing white space */
1718 for (i = (int)STRLEN(line) - 1; i >= 0 && vim_iswhite(line[i]); i--)
1719 {
1720 if (State & REPLACE_FLAG)
1721 replace_join(0); /* remove a NUL from the replace stack */
1722 }
1723 line[i + 1] = NUL;
1724}
1725
1726#if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \
1727 || defined(FEAT_COMMENTS) || defined(PROTO)
1728/*
1729 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1730 * modes correctly. May also be used when not in insert mode at all.
1731 */
1732 void
1733backspace_until_column(col)
1734 int col;
1735{
1736 while ((int)curwin->w_cursor.col > col)
1737 {
1738 curwin->w_cursor.col--;
1739 if (State & REPLACE_FLAG)
1740 replace_do_bs();
1741 else
1742 (void)del_char(FALSE);
1743 }
1744}
1745#endif
1746
1747#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1748/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001749 * CTRL-X pressed in Insert mode.
1750 */
1751 static void
1752ins_ctrl_x()
1753{
1754 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1755 * CTRL-V works like CTRL-N */
1756 if (ctrl_x_mode != CTRL_X_CMDLINE)
1757 {
1758 /* if the next ^X<> won't ADD nothing, then reset
1759 * compl_cont_status */
1760 if (compl_cont_status & CONT_N_ADDS)
1761 compl_cont_status = (compl_cont_status | CONT_INTRPT);
1762 else
1763 compl_cont_status = 0;
1764 /* We're not sure which CTRL-X mode it will be yet */
1765 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1766 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1767 edit_submode_pre = NULL;
1768 showmode();
1769 }
1770}
1771
1772/*
1773 * Return TRUE if the 'dict' or 'tsr' option can be used.
1774 */
1775 static int
1776has_compl_option(dict_opt)
1777 int dict_opt;
1778{
1779 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL)
1780 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
1781 {
1782 ctrl_x_mode = 0;
1783 edit_submode = NULL;
1784 msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
1785 : (char_u *)_("'thesaurus' option is empty"),
1786 hl_attr(HLF_E));
1787 if (emsg_silent == 0)
1788 {
1789 vim_beep();
1790 setcursor();
1791 out_flush();
1792 ui_delay(2000L, FALSE);
1793 }
1794 return FALSE;
1795 }
1796 return TRUE;
1797}
1798
1799/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
1801 * This depends on the current mode.
1802 */
1803 int
1804vim_is_ctrl_x_key(c)
1805 int c;
1806{
1807 /* Always allow ^R - let it's results then be checked */
1808 if (c == Ctrl_R)
1809 return TRUE;
1810
1811 switch (ctrl_x_mode)
1812 {
1813 case 0: /* Not in any CTRL-X mode */
1814 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
1815 case CTRL_X_NOT_DEFINED_YET:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001816 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1818 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
1819 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
Bram Moolenaar488c6512005-08-11 20:09:58 +00001820 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
1821 || c == Ctrl_S || c == 's');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 case CTRL_X_SCROLL:
1823 return (c == Ctrl_Y || c == Ctrl_E);
1824 case CTRL_X_WHOLE_LINE:
1825 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
1826 case CTRL_X_FILES:
1827 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
1828 case CTRL_X_DICTIONARY:
1829 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
1830 case CTRL_X_THESAURUS:
1831 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
1832 case CTRL_X_TAGS:
1833 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
1834#ifdef FEAT_FIND_ID
1835 case CTRL_X_PATH_PATTERNS:
1836 return (c == Ctrl_P || c == Ctrl_N);
1837 case CTRL_X_PATH_DEFINES:
1838 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
1839#endif
1840 case CTRL_X_CMDLINE:
1841 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
1842 || c == Ctrl_X);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001843#ifdef FEAT_COMPL_FUNC
1844 case CTRL_X_FUNCTION:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001845 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001846#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001847 case CTRL_X_OCCULT:
1848 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar488c6512005-08-11 20:09:58 +00001849 case CTRL_X_SPELL:
1850 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 }
1852 EMSG(_(e_internal));
1853 return FALSE;
1854}
1855
1856/*
1857 * This is like ins_compl_add(), but if ic and inf are set, then the
1858 * case of the originally typed text is used, and the case of the completed
1859 * text is infered, ie this tries to work out what case you probably wanted
1860 * the rest of the word to be in -- webb
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001861 * TODO: make this work for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862 */
1863 int
Bram Moolenaar572cb562005-08-05 21:35:02 +00001864ins_compl_add_infercase(str, len, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 char_u *str;
1866 int len;
1867 char_u *fname;
1868 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00001869 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870{
1871 int has_lower = FALSE;
1872 int was_letter = FALSE;
1873 int idx;
1874
1875 if (p_ic && curbuf->b_p_inf && len < IOSIZE)
1876 {
1877 /* Infer case of completed part -- webb */
1878 /* Use IObuff, str would change text in buffer! */
Bram Moolenaarce0842a2005-07-18 21:58:11 +00001879 vim_strncpy(IObuff, str, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880
1881 /* Rule 1: Were any chars converted to lower? */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001882 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001884 if (islower(compl_orig_text[idx]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 {
1886 has_lower = TRUE;
1887 if (isupper(IObuff[idx]))
1888 {
1889 /* Rule 1 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001890 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
1892 break;
1893 }
1894 }
1895 }
1896
1897 /*
1898 * Rule 2: No lower case, 2nd consecutive letter converted to
1899 * upper case.
1900 */
1901 if (!has_lower)
1902 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001903 for (idx = 0; idx < compl_length; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001905 if (was_letter && isupper(compl_orig_text[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 && islower(IObuff[idx]))
1907 {
1908 /* Rule 2 is satisfied */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001909 for (idx = compl_length; idx < len; ++idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
1911 break;
1912 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001913 was_letter = isalpha(compl_orig_text[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 }
1915 }
1916
1917 /* Copy the original case of the part we typed */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001918 STRNCPY(IObuff, compl_orig_text, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919
Bram Moolenaar572cb562005-08-05 21:35:02 +00001920 return ins_compl_add(IObuff, len, fname, dir, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00001922 return ins_compl_add(str, len, fname, dir, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923}
1924
1925/*
1926 * Add a match to the list of matches.
1927 * If the given string is already in the list of completions, then return
1928 * FAIL, otherwise add it to the list and return OK. If there is an error,
Bram Moolenaar572cb562005-08-05 21:35:02 +00001929 * maybe because alloc() returns NULL, then RET_ERROR is returned -- webb.
1930 *
1931 * New:
1932 * If the given string is already in the list of completions, then return
1933 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
1934 * maybe because alloc() returns NULL, then FAIL is returned -- webb.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00001936 int
1937ins_compl_add(str, len, fname, dir, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 char_u *str;
1939 int len;
1940 char_u *fname;
1941 int dir;
Bram Moolenaar572cb562005-08-05 21:35:02 +00001942 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943{
Bram Moolenaar572cb562005-08-05 21:35:02 +00001944 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 ui_breakcheck();
1947 if (got_int)
Bram Moolenaar572cb562005-08-05 21:35:02 +00001948 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 if (len < 0)
1950 len = (int)STRLEN(str);
1951
1952 /*
1953 * If the same match is already present, don't add it.
1954 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001955 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001957 match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 do
1959 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00001960 if ( !(match->cp_flags & ORIGINAL_TEXT)
1961 && STRNCMP(match->cp_str, str, (size_t)len) == 0
1962 && match->cp_str[len] == NUL)
1963 return NOTDONE;
1964 match = match->cp_next;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001965 } while (match != NULL && match != compl_first_match);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 }
1967
1968 /*
1969 * Allocate a new match structure.
1970 * Copy the values to the new match structure.
1971 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00001972 match = (compl_T *)alloc((unsigned)sizeof(compl_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 if (match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00001974 return FAIL;
1975 match->cp_number = -1;
1976 if (flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00001978 match->cp_number = 0;
1979 match->cp_str = compl_orig_text;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00001981 else if ((match->cp_str = vim_strnsave(str, len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 {
1983 vim_free(match);
Bram Moolenaar572cb562005-08-05 21:35:02 +00001984 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 }
1986 /* match-fname is:
Bram Moolenaar572cb562005-08-05 21:35:02 +00001987 * - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
1989 * - NULL otherwise. --Acevedo */
Bram Moolenaar572cb562005-08-05 21:35:02 +00001990 if (fname && compl_curr_match && compl_curr_match->cp_fname
1991 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
1992 match->cp_fname = compl_curr_match->cp_fname;
1993 else if (fname && (match->cp_fname = vim_strsave(fname)) != NULL)
1994 flags |= FREE_FNAME;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 else
Bram Moolenaar572cb562005-08-05 21:35:02 +00001996 match->cp_fname = NULL;
1997 match->cp_flags = flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998
1999 /*
2000 * Link the new match structure in the list of matches.
2001 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002002 if (compl_first_match == NULL)
Bram Moolenaar572cb562005-08-05 21:35:02 +00002003 match->cp_next = match->cp_prev = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 else if (dir == FORWARD)
2005 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002006 match->cp_next = compl_curr_match->cp_next;
2007 match->cp_prev = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008 }
2009 else /* BACKWARD */
2010 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002011 match->cp_next = compl_curr_match;
2012 match->cp_prev = compl_curr_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002014 if (match->cp_next)
2015 match->cp_next->cp_prev = match;
2016 if (match->cp_prev)
2017 match->cp_prev->cp_next = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 else /* if there's nothing before, it is the first match */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002019 compl_first_match = match;
2020 compl_curr_match = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021
2022 return OK;
2023}
2024
2025/*
2026 * Add an array of matches to the list of matches.
2027 * Frees matches[].
2028 */
2029 static void
2030ins_compl_add_matches(num_matches, matches, dir)
2031 int num_matches;
2032 char_u **matches;
2033 int dir;
2034{
2035 int i;
2036 int add_r = OK;
2037 int ldir = dir;
2038
Bram Moolenaar572cb562005-08-05 21:35:02 +00002039 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040 if ((add_r = ins_compl_add(matches[i], -1, NULL, ldir, 0)) == OK)
2041 /* if dir was BACKWARD then honor it just once */
2042 ldir = FORWARD;
2043 FreeWild(num_matches, matches);
2044}
2045
2046/* Make the completion list cyclic.
2047 * Return the number of matches (excluding the original).
2048 */
2049 static int
2050ins_compl_make_cyclic()
2051{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002052 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 int count = 0;
2054
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002055 if (compl_first_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002056 {
2057 /*
2058 * Find the end of the list.
2059 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002060 match = compl_first_match;
2061 /* there's always an entry for the compl_orig_text, it doesn't count. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002062 while (match->cp_next != NULL && match->cp_next != compl_first_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002064 match = match->cp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065 ++count;
2066 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00002067 match->cp_next = compl_first_match;
2068 compl_first_match->cp_prev = match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069 }
2070 return count;
2071}
2072
2073#define DICT_FIRST (1) /* use just first element in "dict" */
2074#define DICT_EXACT (2) /* "dict" is the exact name of a file */
2075/*
2076 * Add any identifiers that match the given pattern to the list of
2077 * completions.
2078 */
2079 static void
2080ins_compl_dictionaries(dict, pat, dir, flags, thesaurus)
2081 char_u *dict;
2082 char_u *pat;
2083 int dir;
2084 int flags;
2085 int thesaurus;
2086{
2087 char_u *ptr;
2088 char_u *buf;
2089 FILE *fp;
2090 regmatch_T regmatch;
2091 int add_r;
2092 char_u **files;
2093 int count;
2094 int i;
2095 int save_p_scs;
2096
2097 buf = alloc(LSIZE);
2098 /* If 'infercase' is set, don't use 'smartcase' here */
2099 save_p_scs = p_scs;
2100 if (curbuf->b_p_inf)
2101 p_scs = FALSE;
2102 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
2103 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2104 regmatch.rm_ic = ignorecase(pat);
2105 while (buf != NULL && regmatch.regprog != NULL && *dict != NUL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002106 && !got_int && !compl_interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 {
2108 /* copy one dictionary file name into buf */
2109 if (flags == DICT_EXACT)
2110 {
2111 count = 1;
2112 files = &dict;
2113 }
2114 else
2115 {
2116 /* Expand wildcards in the dictionary name, but do not allow
2117 * backticks (for security, the 'dict' option may have been set in
2118 * a modeline). */
2119 copy_option_part(&dict, buf, LSIZE, ",");
2120 if (vim_strchr(buf, '`') != NULL
2121 || expand_wildcards(1, &buf, &count, &files,
2122 EW_FILE|EW_SILENT) != OK)
2123 count = 0;
2124 }
2125
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002126 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 {
2128 fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
2129 if (flags != DICT_EXACT)
2130 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002131 vim_snprintf((char *)IObuff, IOSIZE,
2132 _("Scanning dictionary: %s"), (char *)files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2134 }
2135
2136 if (fp != NULL)
2137 {
2138 /*
2139 * Read dictionary file line by line.
2140 * Check each line for a match.
2141 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002142 while (!got_int && !compl_interrupted
2143 && !vim_fgets(buf, LSIZE, fp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 {
2145 ptr = buf;
2146 while (vim_regexec(&regmatch, buf, (colnr_T)(ptr - buf)))
2147 {
2148 ptr = regmatch.startp[0];
2149 ptr = find_word_end(ptr);
2150 add_r = ins_compl_add_infercase(regmatch.startp[0],
2151 (int)(ptr - regmatch.startp[0]),
2152 files[i], dir, 0);
2153 if (thesaurus)
2154 {
2155 char_u *wstart;
2156
2157 /*
2158 * Add the other matches on the line
2159 */
2160 while (!got_int)
2161 {
2162 /* Find start of the next word. Skip white
2163 * space and punctuation. */
2164 ptr = find_word_start(ptr);
2165 if (*ptr == NUL || *ptr == NL)
2166 break;
2167 wstart = ptr;
2168
2169 /* Find end of the word and add it. */
2170#ifdef FEAT_MBYTE
2171 if (has_mbyte)
2172 /* Japanese words may have characters in
2173 * different classes, only separate words
2174 * with single-byte non-word characters. */
2175 while (*ptr != NUL)
2176 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002177 int l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178
2179 if (l < 2 && !vim_iswordc(*ptr))
2180 break;
2181 ptr += l;
2182 }
2183 else
2184#endif
2185 ptr = find_word_end(ptr);
2186 add_r = ins_compl_add_infercase(wstart,
2187 (int)(ptr - wstart), files[i], dir, 0);
2188 }
2189 }
2190 if (add_r == OK)
2191 /* if dir was BACKWARD then honor it just once */
2192 dir = FORWARD;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002193 else if (add_r == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002194 break;
2195 /* avoid expensive call to vim_regexec() when at end
2196 * of line */
2197 if (*ptr == '\n' || got_int)
2198 break;
2199 }
2200 line_breakcheck();
Bram Moolenaar572cb562005-08-05 21:35:02 +00002201 ins_compl_check_keys(50);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 }
2203 fclose(fp);
2204 }
2205 }
2206 if (flags != DICT_EXACT)
2207 FreeWild(count, files);
2208 if (flags)
2209 break;
2210 }
2211 p_scs = save_p_scs;
2212 vim_free(regmatch.regprog);
2213 vim_free(buf);
2214}
2215
2216/*
2217 * Find the start of the next word.
2218 * Returns a pointer to the first char of the word. Also stops at a NUL.
2219 */
2220 char_u *
2221find_word_start(ptr)
2222 char_u *ptr;
2223{
2224#ifdef FEAT_MBYTE
2225 if (has_mbyte)
2226 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002227 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 else
2229#endif
2230 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2231 ++ptr;
2232 return ptr;
2233}
2234
2235/*
2236 * Find the end of the word. Assumes it starts inside a word.
2237 * Returns a pointer to just after the word.
2238 */
2239 char_u *
2240find_word_end(ptr)
2241 char_u *ptr;
2242{
2243#ifdef FEAT_MBYTE
2244 int start_class;
2245
2246 if (has_mbyte)
2247 {
2248 start_class = mb_get_class(ptr);
2249 if (start_class > 1)
2250 while (*ptr != NUL)
2251 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002252 ptr += (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002253 if (mb_get_class(ptr) != start_class)
2254 break;
2255 }
2256 }
2257 else
2258#endif
2259 while (vim_iswordc(*ptr))
2260 ++ptr;
2261 return ptr;
2262}
2263
2264/*
2265 * Free the list of completions
2266 */
2267 static void
2268ins_compl_free()
2269{
Bram Moolenaar572cb562005-08-05 21:35:02 +00002270 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002272 vim_free(compl_pattern);
2273 compl_pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002275 if (compl_first_match == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 return;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002277 compl_curr_match = compl_first_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 do
2279 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002280 match = compl_curr_match;
Bram Moolenaar572cb562005-08-05 21:35:02 +00002281 compl_curr_match = compl_curr_match->cp_next;
2282 vim_free(match->cp_str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 /* several entries may use the same fname, free it just once. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002284 if (match->cp_flags & FREE_FNAME)
2285 vim_free(match->cp_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 vim_free(match);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002287 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
2288 compl_first_match = compl_curr_match = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289}
2290
2291 static void
2292ins_compl_clear()
2293{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002294 compl_cont_status = 0;
2295 compl_started = FALSE;
2296 compl_matches = 0;
2297 vim_free(compl_pattern);
2298 compl_pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 save_sm = -1;
2300 edit_submode_extra = NULL;
2301}
2302
2303/*
2304 * Prepare for Insert mode completion, or stop it.
Bram Moolenaar572cb562005-08-05 21:35:02 +00002305 * Called just after typing a character in Insert mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 */
2307 static void
2308ins_compl_prep(c)
2309 int c;
2310{
2311 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 int temp;
2313 int want_cindent;
2314
2315 /* Forget any previous 'special' messages if this is actually
2316 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
2317 */
2318 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
2319 edit_submode_extra = NULL;
2320
2321 /* Ignore end of Select mode mapping */
2322 if (c == K_SELECT)
2323 return;
2324
2325 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
2326 {
2327 /*
2328 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
2329 * it will be yet. Now we decide.
2330 */
2331 switch (c)
2332 {
2333 case Ctrl_E:
2334 case Ctrl_Y:
2335 ctrl_x_mode = CTRL_X_SCROLL;
2336 if (!(State & REPLACE_FLAG))
2337 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
2338 else
2339 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
2340 edit_submode_pre = NULL;
2341 showmode();
2342 break;
2343 case Ctrl_L:
2344 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2345 break;
2346 case Ctrl_F:
2347 ctrl_x_mode = CTRL_X_FILES;
2348 break;
2349 case Ctrl_K:
2350 ctrl_x_mode = CTRL_X_DICTIONARY;
2351 break;
2352 case Ctrl_R:
2353 /* Simply allow ^R to happen without affecting ^X mode */
2354 break;
2355 case Ctrl_T:
2356 ctrl_x_mode = CTRL_X_THESAURUS;
2357 break;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002358#ifdef FEAT_COMPL_FUNC
2359 case Ctrl_U:
2360 ctrl_x_mode = CTRL_X_FUNCTION;
2361 break;
2362#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002363 case Ctrl_O:
2364 ctrl_x_mode = CTRL_X_OCCULT;
2365 break;
Bram Moolenaar488c6512005-08-11 20:09:58 +00002366 case 's':
2367 case Ctrl_S:
2368 ctrl_x_mode = CTRL_X_SPELL;
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00002369#ifdef FEAT_SYN_HL
2370 spell_back_to_badword();
2371#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00002372 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 case Ctrl_RSB:
2374 ctrl_x_mode = CTRL_X_TAGS;
2375 break;
2376#ifdef FEAT_FIND_ID
2377 case Ctrl_I:
2378 case K_S_TAB:
2379 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
2380 break;
2381 case Ctrl_D:
2382 ctrl_x_mode = CTRL_X_PATH_DEFINES;
2383 break;
2384#endif
2385 case Ctrl_V:
2386 case Ctrl_Q:
2387 ctrl_x_mode = CTRL_X_CMDLINE;
2388 break;
2389 case Ctrl_P:
2390 case Ctrl_N:
2391 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
2392 * just started ^X mode, or there were enough ^X's to cancel
2393 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
2394 * do normal expansion when interrupting a different mode (say
2395 * ^X^F^X^P or ^P^X^X^P, see below)
2396 * nothing changes if interrupting mode 0, (eg, the flag
2397 * doesn't change when going to ADDING mode -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002398 if (!(compl_cont_status & CONT_INTRPT))
2399 compl_cont_status |= CONT_LOCAL;
2400 else if (compl_cont_mode != 0)
2401 compl_cont_status &= ~CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 /* FALLTHROUGH */
2403 default:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002404 /* If we have typed at least 2 ^X's... for modes != 0, we set
2405 * compl_cont_status = 0 (eg, as if we had just started ^X
2406 * mode).
2407 * For mode 0, we set "compl_cont_mode" to an impossible
2408 * value, in both cases ^X^X can be used to restart the same
2409 * mode (avoiding ADDING mode).
2410 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
2411 * 'complete' and local ^P expansions respectively.
2412 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
2413 * mode -- Acevedo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 if (c == Ctrl_X)
2415 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002416 if (compl_cont_mode != 0)
2417 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002419 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 }
2421 ctrl_x_mode = 0;
2422 edit_submode = NULL;
2423 showmode();
2424 break;
2425 }
2426 }
2427 else if (ctrl_x_mode != 0)
2428 {
2429 /* We're already in CTRL-X mode, do we stay in it? */
2430 if (!vim_is_ctrl_x_key(c))
2431 {
2432 if (ctrl_x_mode == CTRL_X_SCROLL)
2433 ctrl_x_mode = 0;
2434 else
2435 ctrl_x_mode = CTRL_X_FINISHED;
2436 edit_submode = NULL;
2437 }
2438 showmode();
2439 }
2440
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002441 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 {
2443 /* Show error message from attempted keyword completion (probably
2444 * 'Pattern not found') until another key is hit, then go back to
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002445 * showing what mode we are in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 showmode();
2447 if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R)
2448 || ctrl_x_mode == CTRL_X_FINISHED)
2449 {
2450 /* Get here when we have finished typing a sequence of ^N and
2451 * ^P or other completion characters in CTRL-X mode. Free up
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002452 * memory that was used, and make sure we can redo the insert. */
2453 if (compl_curr_match != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002455 char_u *p;
2456
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 /*
2458 * If any of the original typed text has been changed,
2459 * eg when ignorecase is set, we must add back-spaces to
2460 * the redo buffer. We add as few as necessary to delete
2461 * just the part of the original text that has changed.
2462 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00002463 ptr = compl_curr_match->cp_str;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002464 p = compl_orig_text;
2465 while (*p && *p == *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002467 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 ++ptr;
2469 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002470 for (temp = 0; p[temp]; ++temp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 AppendCharToRedobuff(K_BS);
2472 AppendToRedobuffLit(ptr);
2473 }
2474
2475#ifdef FEAT_CINDENT
2476 want_cindent = (can_cindent && cindent_on());
2477#endif
2478 /*
2479 * When completing whole lines: fix indent for 'cindent'.
2480 * Otherwise, break line if it's too long.
2481 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002482 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483 {
2484#ifdef FEAT_CINDENT
2485 /* re-indent the current line */
2486 if (want_cindent)
2487 {
2488 do_c_expr_indent();
2489 want_cindent = FALSE; /* don't do it again */
2490 }
2491#endif
2492 }
2493 else
2494 {
2495 /* put the cursor on the last char, for 'tw' formatting */
2496 curwin->w_cursor.col--;
2497 if (stop_arrow() == OK)
2498 insertchar(NUL, 0, -1);
2499 curwin->w_cursor.col++;
2500 }
2501
2502 auto_format(FALSE, TRUE);
2503
2504 ins_compl_free();
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002505 compl_started = FALSE;
2506 compl_matches = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 msg_clr_cmdline(); /* necessary for "noshowmode" */
2508 ctrl_x_mode = 0;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002509 if (save_sm >= 0)
2510 p_sm = save_sm;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002511 if (edit_submode != NULL)
2512 {
2513 edit_submode = NULL;
2514 showmode();
2515 }
2516
2517#ifdef FEAT_CINDENT
2518 /*
2519 * Indent now if a key was typed that is in 'cinkeys'.
2520 */
2521 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
2522 do_c_expr_indent();
2523#endif
2524 }
2525 }
2526
2527 /* reset continue_* if we left expansion-mode, if we stay they'll be
2528 * (re)set properly in ins_complete() */
2529 if (!vim_is_ctrl_x_key(c))
2530 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002531 compl_cont_status = 0;
2532 compl_cont_mode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 }
2534}
2535
2536/*
2537 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
2538 * (depending on flag) starting from buf and looking for a non-scanned
2539 * buffer (other than curbuf). curbuf is special, if it is called with
2540 * buf=curbuf then it has to be the first call for a given flag/expansion.
2541 *
2542 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
2543 */
2544 static buf_T *
2545ins_compl_next_buf(buf, flag)
2546 buf_T *buf;
2547 int flag;
2548{
2549#ifdef FEAT_WINDOWS
2550 static win_T *wp;
2551#endif
2552
2553 if (flag == 'w') /* just windows */
2554 {
2555#ifdef FEAT_WINDOWS
2556 if (buf == curbuf) /* first call for this flag/expansion */
2557 wp = curwin;
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00002558 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 && wp->w_buffer->b_scanned)
2560 ;
2561 buf = wp->w_buffer;
2562#else
2563 buf = curbuf;
2564#endif
2565 }
2566 else
2567 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
2568 * (unlisted buffers)
2569 * When completing whole lines skip unloaded buffers. */
Bram Moolenaar1f8a5f02005-07-01 22:41:52 +00002570 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 && ((flag == 'U'
2572 ? buf->b_p_bl
2573 : (!buf->b_p_bl
2574 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
2575 || buf->b_scanned
2576 || (buf->b_ml.ml_mfp == NULL
2577 && ctrl_x_mode == CTRL_X_WHOLE_LINE)))
2578 ;
2579 return buf;
2580}
2581
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002582#ifdef FEAT_COMPL_FUNC
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002583static int expand_by_function __ARGS((int col, char_u *base, char_u ***matches));
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002584
2585/*
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002586 * Execute user defined complete function 'completefunc', and get matches in
2587 * "matches".
2588 * Return value is number of matches.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002589 */
2590 static int
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002591expand_by_function(col, base, matches)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002592 int col;
2593 char_u *base;
2594 char_u ***matches;
2595{
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002596 list_T *matchlist;
2597 char_u colbuf[30];
2598 char_u *args[3];
2599 listitem_T *li;
2600 garray_T ga;
2601 char_u *p;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002602
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002603 if (*curbuf->b_p_cfu == NUL)
2604 return 0;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002605
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002606 /* Call 'completefunc' to obtain the list of matches. */
2607 args[0] = (char_u *)"0";
2608 sprintf((char *)colbuf, "%d", col + (int)STRLEN(base));
2609 args[1] = colbuf;
2610 args[2] = base;
2611
2612 matchlist = call_func_retlist(curbuf->b_p_cfu, 3, args, FALSE);
2613 if (matchlist == NULL)
2614 return 0;
2615
2616 /* Go through the List with matches and put them in an array. */
2617 ga_init2(&ga, (int)sizeof(char_u *), 8);
2618 for (li = matchlist->lv_first; li != NULL; li = li->li_next)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002619 {
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002620 p = get_tv_string_chk(&li->li_tv);
2621 if (p != NULL && *p != NUL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002622 {
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002623 if (ga_grow(&ga, 1) == FAIL)
2624 break;
2625 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strsave(p);
2626 ++ga.ga_len;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002627 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002628 }
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002629
2630 list_unref(matchlist);
2631 *matches = (char_u **)ga.ga_data;
2632 return ga.ga_len;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002633}
2634#endif /* FEAT_COMPL_FUNC */
2635
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002636static int expand_occult __ARGS((linenr_T lnum, int col, char_u *base, char_u ***matches));
2637
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002639 * Perform occult completion'
2640 * Return value is number of candidates and array of candidates as "matchp".
2641 */
2642 static int
2643expand_occult(lnum, col, pat, matchp)
2644 linenr_T lnum;
2645 int col;
2646 char_u *pat;
2647 char_u ***matchp;
2648{
2649 int num_matches;
2650
2651 /* Use tag completion for now. */
2652 if (find_tags(pat, &num_matches, matchp,
2653 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
2654 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
2655 TAG_MANY, curbuf->b_ffname) == FAIL)
2656 return 0;
2657 return num_matches;
2658}
2659
2660/*
2661 * Get the next expansion(s), using "compl_pattern".
2662 * The search starts at position "ini" in curbuf and in the direction dir.
2663 * When "compl_started" is FALSE start at that position, otherwise
2664 * continue where we stopped searching before.
2665 * This may return before finding all the matches.
2666 * Return the total number of matches or -1 if still unknown -- Acevedo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 */
2668 static int
2669ins_compl_get_exp(ini, dir)
2670 pos_T *ini;
2671 int dir;
2672{
2673 static pos_T first_match_pos;
2674 static pos_T last_match_pos;
2675 static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002676 static int found_all = FALSE; /* Found all matches of a
2677 certain type. */
2678 static buf_T *ins_buf = NULL; /* buffer being scanned */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679
Bram Moolenaar572cb562005-08-05 21:35:02 +00002680 pos_T *pos;
2681 char_u **matches;
2682 int save_p_scs;
2683 int save_p_ws;
2684 int save_p_ic;
2685 int i;
2686 int num_matches;
2687 int len;
2688 int found_new_match;
2689 int type = ctrl_x_mode;
2690 char_u *ptr;
2691 char_u *dict = NULL;
2692 int dict_f = 0;
2693 compl_T *old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002695 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 {
2697 for (ins_buf = firstbuf; ins_buf != NULL; ins_buf = ins_buf->b_next)
2698 ins_buf->b_scanned = 0;
2699 found_all = FALSE;
2700 ins_buf = curbuf;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002701 e_cpt = (compl_cont_status & CONT_LOCAL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002702 ? (char_u *)"." : curbuf->b_p_cpt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 last_match_pos = first_match_pos = *ini;
2704 }
2705
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002706 old_match = compl_curr_match; /* remember the last current match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 pos = (dir == FORWARD) ? &last_match_pos : &first_match_pos;
2708 /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
2709 for (;;)
2710 {
2711 found_new_match = FAIL;
2712
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002713 /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 * or if found_all says this entry is done. For ^X^L only use the
2715 * entries from 'complete' that look in loaded buffers. */
2716 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002717 && (!compl_started || found_all))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 {
2719 found_all = FALSE;
2720 while (*e_cpt == ',' || *e_cpt == ' ')
2721 e_cpt++;
2722 if (*e_cpt == '.' && !curbuf->b_scanned)
2723 {
2724 ins_buf = curbuf;
2725 first_match_pos = *ini;
2726 /* So that ^N can match word immediately after cursor */
2727 if (ctrl_x_mode == 0)
2728 dec(&first_match_pos);
2729 last_match_pos = first_match_pos;
2730 type = 0;
2731 }
2732 else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
2733 && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
2734 {
2735 /* Scan a buffer, but not the current one. */
2736 if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
2737 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002738 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 first_match_pos.col = last_match_pos.col = 0;
2740 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
2741 last_match_pos.lnum = 0;
2742 type = 0;
2743 }
2744 else /* unloaded buffer, scan like dictionary */
2745 {
2746 found_all = TRUE;
2747 if (ins_buf->b_fname == NULL)
2748 continue;
2749 type = CTRL_X_DICTIONARY;
2750 dict = ins_buf->b_fname;
2751 dict_f = DICT_EXACT;
2752 }
Bram Moolenaar555b2802005-05-19 21:08:39 +00002753 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 ins_buf->b_fname == NULL
2755 ? buf_spname(ins_buf)
2756 : ins_buf->b_sfname == NULL
2757 ? (char *)ins_buf->b_fname
2758 : (char *)ins_buf->b_sfname);
2759 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2760 }
2761 else if (*e_cpt == NUL)
2762 break;
2763 else
2764 {
2765 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2766 type = -1;
2767 else if (*e_cpt == 'k' || *e_cpt == 's')
2768 {
2769 if (*e_cpt == 'k')
2770 type = CTRL_X_DICTIONARY;
2771 else
2772 type = CTRL_X_THESAURUS;
2773 if (*++e_cpt != ',' && *e_cpt != NUL)
2774 {
2775 dict = e_cpt;
2776 dict_f = DICT_FIRST;
2777 }
2778 }
2779#ifdef FEAT_FIND_ID
2780 else if (*e_cpt == 'i')
2781 type = CTRL_X_PATH_PATTERNS;
2782 else if (*e_cpt == 'd')
2783 type = CTRL_X_PATH_DEFINES;
2784#endif
2785 else if (*e_cpt == ']' || *e_cpt == 't')
2786 {
2787 type = CTRL_X_TAGS;
2788 sprintf((char*)IObuff, _("Scanning tags."));
2789 msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
2790 }
2791 else
2792 type = -1;
2793
2794 /* in any case e_cpt is advanced to the next entry */
2795 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
2796
2797 found_all = TRUE;
2798 if (type == -1)
2799 continue;
2800 }
2801 }
2802
2803 switch (type)
2804 {
2805 case -1:
2806 break;
2807#ifdef FEAT_FIND_ID
2808 case CTRL_X_PATH_PATTERNS:
2809 case CTRL_X_PATH_DEFINES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002810 find_pattern_in_path(compl_pattern, dir,
2811 (int)STRLEN(compl_pattern), FALSE, FALSE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 (type == CTRL_X_PATH_DEFINES
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002813 && !(compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
2815 (linenr_T)1, (linenr_T)MAXLNUM);
2816 break;
2817#endif
2818
2819 case CTRL_X_DICTIONARY:
2820 case CTRL_X_THESAURUS:
2821 ins_compl_dictionaries(
2822 dict ? dict
2823 : (type == CTRL_X_THESAURUS
2824 ? (*curbuf->b_p_tsr == NUL
2825 ? p_tsr
2826 : curbuf->b_p_tsr)
2827 : (*curbuf->b_p_dict == NUL
2828 ? p_dict
2829 : curbuf->b_p_dict)),
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002830 compl_pattern, dir,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831 dict ? dict_f : 0, type == CTRL_X_THESAURUS);
2832 dict = NULL;
2833 break;
2834
2835 case CTRL_X_TAGS:
2836 /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
2837 save_p_ic = p_ic;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002838 p_ic = ignorecase(compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839
2840 /* Find up to TAG_MANY matches. Avoids that an enourmous number
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002841 * of matches is found when compl_pattern is empty */
2842 if (find_tags(compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 TAG_REGEXP | TAG_NAMES | TAG_NOIC |
2844 TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
2845 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
2846 {
2847 ins_compl_add_matches(num_matches, matches, dir);
2848 }
2849 p_ic = save_p_ic;
2850 break;
2851
2852 case CTRL_X_FILES:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002853 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
2855 {
2856
2857 /* May change home directory back to "~". */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002858 tilde_replace(compl_pattern, num_matches, matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 ins_compl_add_matches(num_matches, matches, dir);
2860 }
2861 break;
2862
2863 case CTRL_X_CMDLINE:
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002864 if (expand_cmdline(&compl_xp, compl_pattern,
2865 (int)STRLEN(compl_pattern),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866 &num_matches, &matches) == EXPAND_OK)
2867 ins_compl_add_matches(num_matches, matches, dir);
2868 break;
2869
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002870#ifdef FEAT_COMPL_FUNC
2871 case CTRL_X_FUNCTION:
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00002872 num_matches = expand_by_function(first_match_pos.col,
2873 compl_pattern, &matches);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002874 if (num_matches > 0)
2875 ins_compl_add_matches(num_matches, matches, dir);
2876 break;
2877#endif
2878
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002879 case CTRL_X_OCCULT:
2880 num_matches = expand_occult(first_match_pos.lnum,
2881 first_match_pos.col, compl_pattern, &matches);
2882 if (num_matches > 0)
2883 ins_compl_add_matches(num_matches, matches, dir);
2884 break;
2885
Bram Moolenaar488c6512005-08-11 20:09:58 +00002886 case CTRL_X_SPELL:
2887#ifdef FEAT_SYN_HL
2888 num_matches = expand_spelling(first_match_pos.lnum,
2889 first_match_pos.col, compl_pattern, &matches);
2890 if (num_matches > 0)
2891 ins_compl_add_matches(num_matches, matches, dir);
2892#endif
2893 break;
2894
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 default: /* normal ^P/^N and ^X^L */
2896 /*
2897 * If 'infercase' is set, don't use 'smartcase' here
2898 */
2899 save_p_scs = p_scs;
2900 if (ins_buf->b_p_inf)
2901 p_scs = FALSE;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002902
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 /* buffers other than curbuf are scanned from the beginning or the
2904 * end but never from the middle, thus setting nowrapscan in this
2905 * buffers is a good idea, on the other hand, we always set
2906 * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
2907 save_p_ws = p_ws;
2908 if (ins_buf != curbuf)
2909 p_ws = FALSE;
2910 else if (*e_cpt == '.')
2911 p_ws = TRUE;
2912 for (;;)
2913 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00002914 int flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915
2916 /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that has
2917 * added a word that was at the beginning of the line */
2918 if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002919 || (compl_cont_status & CONT_SOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920 found_new_match = search_for_exact_line(ins_buf, pos,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002921 dir, compl_pattern);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 else
2923 found_new_match = searchit(NULL, ins_buf, pos, dir,
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002924 compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 RE_LAST);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002926 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002928 /* set compl_started even on fail */
2929 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930 first_match_pos = *pos;
2931 last_match_pos = *pos;
2932 }
2933 else if (first_match_pos.lnum == last_match_pos.lnum
2934 && first_match_pos.col == last_match_pos.col)
2935 found_new_match = FAIL;
2936 if (found_new_match == FAIL)
2937 {
2938 if (ins_buf == curbuf)
2939 found_all = TRUE;
2940 break;
2941 }
2942
2943 /* when ADDING, the text before the cursor matches, skip it */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002944 if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 && ini->lnum == pos->lnum
2946 && ini->col == pos->col)
2947 continue;
2948 ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
2949 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
2950 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002951 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 {
2953 if (pos->lnum >= ins_buf->b_ml.ml_line_count)
2954 continue;
2955 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
2956 if (!p_paste)
2957 ptr = skipwhite(ptr);
2958 }
2959 len = (int)STRLEN(ptr);
2960 }
2961 else
2962 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002963 char_u *tmp_ptr = ptr;
2964
2965 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002967 tmp_ptr += compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968 /* Skip if already inside a word. */
2969 if (vim_iswordp(tmp_ptr))
2970 continue;
2971 /* Find start of next word. */
2972 tmp_ptr = find_word_start(tmp_ptr);
2973 }
2974 /* Find end of this word. */
2975 tmp_ptr = find_word_end(tmp_ptr);
2976 len = (int)(tmp_ptr - ptr);
2977
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002978 if ((compl_cont_status & CONT_ADDING)
2979 && len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 {
2981 if (pos->lnum < ins_buf->b_ml.ml_line_count)
2982 {
2983 /* Try next line, if any. the new word will be
2984 * "join" as if the normal command "J" was used.
2985 * IOSIZE is always greater than
Bram Moolenaar4be06f92005-07-29 22:36:03 +00002986 * compl_length, so the next STRNCPY always
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 * works -- Acevedo */
2988 STRNCPY(IObuff, ptr, len);
2989 ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
2990 tmp_ptr = ptr = skipwhite(ptr);
2991 /* Find start of next word. */
2992 tmp_ptr = find_word_start(tmp_ptr);
2993 /* Find end of next word. */
2994 tmp_ptr = find_word_end(tmp_ptr);
2995 if (tmp_ptr > ptr)
2996 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002997 if (*ptr != ')' && IObuff[len - 1] != TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002999 if (IObuff[len - 1] != ' ')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 IObuff[len++] = ' ';
3001 /* IObuf =~ "\k.* ", thus len >= 2 */
3002 if (p_js
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003003 && (IObuff[len - 2] == '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 || (vim_strchr(p_cpo, CPO_JOINSP)
3005 == NULL
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003006 && (IObuff[len - 2] == '?'
3007 || IObuff[len - 2] == '!'))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008 IObuff[len++] = ' ';
3009 }
3010 /* copy as much as posible of the new word */
3011 if (tmp_ptr - ptr >= IOSIZE - len)
3012 tmp_ptr = ptr + IOSIZE - len - 1;
3013 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3014 len += (int)(tmp_ptr - ptr);
Bram Moolenaar572cb562005-08-05 21:35:02 +00003015 flags |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 }
3017 IObuff[len] = NUL;
3018 ptr = IObuff;
3019 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003020 if (len == compl_length)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 continue;
3022 }
3023 }
3024 if (ins_compl_add_infercase(ptr, len,
3025 ins_buf == curbuf ? NULL : ins_buf->b_sfname,
Bram Moolenaar572cb562005-08-05 21:35:02 +00003026 dir, flags) != NOTDONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027 {
3028 found_new_match = OK;
3029 break;
3030 }
3031 }
3032 p_scs = save_p_scs;
3033 p_ws = save_p_ws;
3034 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003035 /* check if compl_curr_match has changed, (e.g. other type of
3036 * expansion added somenthing) */
3037 if (compl_curr_match != old_match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 found_new_match = OK;
3039
3040 /* break the loop for specialized modes (use 'complete' just for the
3041 * generic ctrl_x_mode == 0) or when we've found a new match */
3042 if ((ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003043 || found_new_match != FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 break;
3045
3046 /* Mark a buffer scanned when it has been scanned completely */
3047 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
3048 ins_buf->b_scanned = TRUE;
3049
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003050 compl_started = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003052 compl_started = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053
3054 if ((ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
3055 && *e_cpt == NUL) /* Got to end of 'complete' */
3056 found_new_match = FAIL;
3057
3058 i = -1; /* total of matches, unknown */
3059 if (found_new_match == FAIL
3060 || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
3061 i = ins_compl_make_cyclic();
3062
3063 /* If several matches were added (FORWARD) or the search failed and has
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003064 * just been made cyclic then we have to move compl_curr_match to the next
3065 * or previous entry (if any) -- Acevedo */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003066 compl_curr_match = dir == FORWARD ? old_match->cp_next : old_match->cp_prev;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003067 if (compl_curr_match == NULL)
3068 compl_curr_match = old_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 return i;
3070}
3071
3072/* Delete the old text being completed. */
3073 static void
3074ins_compl_delete()
3075{
3076 int i;
3077
3078 /*
3079 * In insert mode: Delete the typed part.
3080 * In replace mode: Put the old characters back, if any.
3081 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003082 i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 backspace_until_column(i);
3084 changed_cline_bef_curs();
3085}
3086
3087/* Insert the new text being completed. */
3088 static void
3089ins_compl_insert()
3090{
Bram Moolenaar572cb562005-08-05 21:35:02 +00003091 ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092}
3093
3094/*
3095 * Fill in the next completion in the current direction.
Bram Moolenaar572cb562005-08-05 21:35:02 +00003096 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
3097 * get more completions. If it is FALSE, then we just do nothing when there
3098 * are no more completions in a given direction. The latter case is used when
3099 * we are still in the middle of finding completions, to allow browsing
3100 * through the ones found so far.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 * Return the total number of matches, or -1 if still unknown -- webb.
3102 *
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003103 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
3104 * compl_shown_match here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003105 *
3106 * Note that this function may be called recursively once only. First with
Bram Moolenaar572cb562005-08-05 21:35:02 +00003107 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
3108 * calls this function with "allow_get_expansion" FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109 */
3110 static int
3111ins_compl_next(allow_get_expansion)
3112 int allow_get_expansion;
3113{
3114 int num_matches = -1;
3115 int i;
3116
3117 if (allow_get_expansion)
3118 {
3119 /* Delete old text to be replaced */
3120 ins_compl_delete();
3121 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003122 compl_pending = FALSE;
Bram Moolenaar572cb562005-08-05 21:35:02 +00003123 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
3124 compl_shown_match = compl_shown_match->cp_next;
3125 else if (compl_shows_dir == BACKWARD && compl_shown_match->cp_prev != NULL)
3126 compl_shown_match = compl_shown_match->cp_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127 else
3128 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003129 compl_pending = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 if (allow_get_expansion)
3131 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003132 num_matches = ins_compl_get_exp(&compl_startpos,
3133 compl_direction);
3134 if (compl_pending)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003136 if (compl_direction == compl_shows_dir)
3137 compl_shown_match = compl_curr_match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 }
3139 }
3140 else
3141 return -1;
3142 }
3143
3144 /* Insert the text of the new completion */
3145 ins_compl_insert();
3146
3147 if (!allow_get_expansion)
3148 {
3149 /* Display the current match. */
3150 update_screen(0);
3151
3152 /* Delete old text to be replaced, since we're still searching and
3153 * don't want to match ourselves! */
3154 ins_compl_delete();
3155 }
3156
3157 /*
3158 * Show the file name for the match (if any)
3159 * Truncate the file name to avoid a wait for return.
3160 */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003161 if (compl_shown_match->cp_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162 {
3163 STRCPY(IObuff, "match in file ");
Bram Moolenaar572cb562005-08-05 21:35:02 +00003164 i = (vim_strsize(compl_shown_match->cp_fname) + 16) - sc_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 if (i <= 0)
3166 i = 0;
3167 else
3168 STRCAT(IObuff, "<");
Bram Moolenaar572cb562005-08-05 21:35:02 +00003169 STRCAT(IObuff, compl_shown_match->cp_fname + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 msg(IObuff);
3171 redraw_cmdline = FALSE; /* don't overwrite! */
3172 }
3173
3174 return num_matches;
3175}
3176
3177/*
3178 * Call this while finding completions, to check whether the user has hit a key
3179 * that should change the currently displayed completion, or exit completion
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003180 * mode. Also, when compl_pending is TRUE, show a completion as soon as
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 * possible. -- webb
Bram Moolenaar572cb562005-08-05 21:35:02 +00003182 * "frequency" specifies out of how many calls we actually check.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183 */
3184 void
Bram Moolenaar572cb562005-08-05 21:35:02 +00003185ins_compl_check_keys(frequency)
3186 int frequency;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187{
3188 static int count = 0;
3189
3190 int c;
3191
3192 /* Don't check when reading keys from a script. That would break the test
3193 * scripts */
3194 if (using_script())
3195 return;
3196
3197 /* Only do this at regular intervals */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003198 if (++count < frequency)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 return;
3200 count = 0;
3201
3202 ++no_mapping;
3203 c = vpeekc_any();
3204 --no_mapping;
3205 if (c != NUL)
3206 {
3207 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
3208 {
3209 c = safe_vgetc(); /* Eat the character */
3210 if (c == Ctrl_P || c == Ctrl_L)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003211 compl_shows_dir = BACKWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003213 compl_shows_dir = FORWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 (void)ins_compl_next(FALSE);
3215 }
3216 else if (c != Ctrl_R)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003217 compl_interrupted = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003219 if (compl_pending && !got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 (void)ins_compl_next(FALSE);
3221}
3222
3223/*
3224 * Do Insert mode completion.
3225 * Called when character "c" was typed, which has a meaning for completion.
3226 * Returns OK if completion was done, FAIL if something failed (out of mem).
3227 */
3228 static int
3229ins_complete(c)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003230 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003232 char_u *line;
3233 int startcol = 0; /* column where searched text starts */
3234 colnr_T curs_col; /* cursor column */
3235 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237 if (c == Ctrl_P || c == Ctrl_L)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003238 compl_direction = BACKWARD;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003240 compl_direction = FORWARD;
3241 if (!compl_started)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 {
3243 /* First time we hit ^N or ^P (in a row, I mean) */
3244
3245 /* Turn off 'sm' so we don't show matches with ^X^L */
3246 save_sm = p_sm;
3247 p_sm = FALSE;
3248
3249 did_ai = FALSE;
3250#ifdef FEAT_SMARTINDENT
3251 did_si = FALSE;
3252 can_si = FALSE;
3253 can_si_back = FALSE;
3254#endif
3255 if (stop_arrow() == FAIL)
3256 return FAIL;
3257
3258 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003259 curs_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260
3261 /* if this same ctrl_x_mode has been interrupted use the text from
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003262 * "compl_startpos" to the cursor as a pattern to add a new word
3263 * instead of expand the one before the cursor, in word-wise if
3264 * "compl_startpos"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 * is not in the same line as the cursor then fix it (the line has
3266 * been split because it was longer than 'tw'). if SOL is set then
3267 * skip the previous pattern, a word at the beginning of the line has
3268 * been inserted, we'll look for that -- Acevedo. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003269 if ((compl_cont_status & CONT_INTRPT) && compl_cont_mode == ctrl_x_mode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270 {
3271 /*
3272 * it is a continued search
3273 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003274 compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275 if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
3276 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
3277 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003278 if (compl_startpos.lnum != curwin->w_cursor.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003280 /* line (probably) wrapped, set compl_startpos to the
3281 * first non_blank in the line, if it is not a wordchar
3282 * include it to get a better pattern, but then we don't
3283 * want the "\\<" prefix, check it bellow */
3284 compl_col = (colnr_T)(skipwhite(line) - line);
3285 compl_startpos.col = compl_col;
3286 compl_startpos.lnum = curwin->w_cursor.lnum;
3287 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 }
3289 else
3290 {
3291 /* S_IPOS was set when we inserted a word that was at the
3292 * beginning of the line, which means that we'll go to SOL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003293 * mode but first we need to redefine compl_startpos */
3294 if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003296 compl_cont_status |= CONT_SOL;
3297 compl_startpos.col = (colnr_T)(skipwhite(
3298 line + compl_length
3299 + compl_startpos.col) - line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003301 compl_col = compl_startpos.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003303 compl_length = curwin->w_cursor.col - (int)compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 /* IObuf is used to add a "word from the next line" would we
3305 * have enough space? just being paranoic */
3306#define MIN_SPACE 75
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003307 if (compl_length > (IOSIZE - MIN_SPACE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003309 compl_cont_status &= ~CONT_SOL;
3310 compl_length = (IOSIZE - MIN_SPACE);
3311 compl_col = curwin->w_cursor.col - compl_length;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003313 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
3314 if (compl_length < 1)
3315 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 }
3317 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003318 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003320 compl_cont_status = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 }
3322 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003323 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003325 if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003327 compl_cont_mode = ctrl_x_mode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003329 compl_cont_status = 0;
3330 compl_cont_status |= CONT_N_ADDS;
3331 compl_startpos = curwin->w_cursor;
3332 startcol = (int)curs_col;
3333 compl_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 }
3335
3336 /* Work out completion pattern and original text -- webb */
3337 if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
3338 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003339 if ((compl_cont_status & CONT_SOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 || ctrl_x_mode == CTRL_X_PATH_DEFINES)
3341 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003342 if (!(compl_cont_status & CONT_ADDING))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003344 while (--startcol >= 0 && vim_isIDc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003346 compl_col += ++startcol;
3347 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348 }
3349 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003350 compl_pattern = str_foldcase(line + compl_col,
3351 compl_length, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003353 compl_pattern = vim_strnsave(line + compl_col,
3354 compl_length);
3355 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 return FAIL;
3357 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003358 else if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359 {
3360 char_u *prefix = (char_u *)"\\<";
3361
3362 /* we need 3 extra chars, 1 for the NUL and
3363 * 2 >= strlen(prefix) -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003364 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
3365 compl_length) + 3);
3366 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003368 if (!vim_iswordp(line + compl_col)
3369 || (compl_col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 && (
3371#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003372 vim_iswordp(mb_prevptr(line, line + compl_col))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003374 vim_iswordc(line[compl_col - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375#endif
3376 )))
3377 prefix = (char_u *)"";
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003378 STRCPY((char *)compl_pattern, prefix);
3379 (void)quote_meta(compl_pattern + STRLEN(prefix),
3380 line + compl_col, compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003382 else if (--startcol < 0 ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383#ifdef FEAT_MBYTE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003384 !vim_iswordp(mb_prevptr(line, line + startcol + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385#else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003386 !vim_iswordc(line[startcol])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387#endif
3388 )
3389 {
3390 /* Match any word of at least two chars */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003391 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
3392 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003394 compl_col += curs_col;
3395 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 }
3397 else
3398 {
3399#ifdef FEAT_MBYTE
3400 /* Search the point of change class of multibyte character
3401 * or not a word single byte character backward. */
3402 if (has_mbyte)
3403 {
3404 int base_class;
3405 int head_off;
3406
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003407 startcol -= (*mb_head_off)(line, line + startcol);
3408 base_class = mb_get_class(line + startcol);
3409 while (--startcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003411 head_off = (*mb_head_off)(line, line + startcol);
3412 if (base_class != mb_get_class(line + startcol
3413 - head_off))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414 break;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003415 startcol -= head_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 }
3417 }
3418 else
3419#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003420 while (--startcol >= 0 && vim_iswordc(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003422 compl_col += ++startcol;
3423 compl_length = (int)curs_col - startcol;
3424 if (compl_length == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425 {
3426 /* Only match word with at least two chars -- webb
3427 * there's no need to call quote_meta,
3428 * alloc(7) is enough -- Acevedo
3429 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003430 compl_pattern = alloc(7);
3431 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003433 STRCPY((char *)compl_pattern, "\\<");
3434 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
3435 STRCAT((char *)compl_pattern, "\\k");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436 }
3437 else
3438 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003439 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
3440 compl_length) + 3);
3441 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003443 STRCPY((char *)compl_pattern, "\\<");
3444 (void)quote_meta(compl_pattern + 2, line + compl_col,
3445 compl_length);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 }
3447 }
3448 }
3449 else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3450 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003451 compl_col = skipwhite(line) - line;
3452 compl_length = (int)curs_col - (int)compl_col;
3453 if (compl_length < 0) /* cursor in indent: empty pattern */
3454 compl_length = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455 if (p_ic)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003456 compl_pattern = str_foldcase(line + compl_col, compl_length,
3457 NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003459 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3460 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 return FAIL;
3462 }
3463 else if (ctrl_x_mode == CTRL_X_FILES)
3464 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003465 while (--startcol >= 0 && vim_isfilec(line[startcol]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 ;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003467 compl_col += ++startcol;
3468 compl_length = (int)curs_col - startcol;
3469 compl_pattern = addstar(line + compl_col, compl_length,
3470 EXPAND_FILES);
3471 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472 return FAIL;
3473 }
3474 else if (ctrl_x_mode == CTRL_X_CMDLINE)
3475 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003476 compl_pattern = vim_strnsave(line, curs_col);
3477 if (compl_pattern == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003479 set_cmd_context(&compl_xp, compl_pattern,
3480 (int)STRLEN(compl_pattern), curs_col);
3481 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
3482 || compl_xp.xp_context == EXPAND_NOTHING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483 return FAIL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003484 startcol = (int)(compl_xp.xp_pattern - compl_pattern);
3485 compl_col = startcol;
3486 compl_length = curs_col - startcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487 }
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003488#ifdef FEAT_COMPL_FUNC
3489 else if (ctrl_x_mode == CTRL_X_FUNCTION)
3490 {
3491 /*
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003492 * Call user defined function 'completefunc' with "a:findstart" is
3493 * 1 to obtain the length of text to use for completion.
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003494 */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003495 char_u colbuf[30];
3496 char_u *args[3];
3497 int col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003498
3499 /* Call 'completefunc' and get pattern length as a string */
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003500 if (*curbuf->b_p_cfu == NUL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003501 return FAIL;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003502
3503 args[0] = (char_u *)"1";
3504 sprintf((char *)colbuf, "%d", (int)curs_col);
3505 args[1] = colbuf;
3506 args[2] = NULL;
3507
3508 col = call_func_retnr(curbuf->b_p_cfu, 3, args, FALSE);
3509 if (col < 0)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003510 return FAIL;
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003511 compl_col = col;
3512 if ((colnr_T)compl_col > curs_col)
3513 compl_col = curs_col;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003514
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003515 /* Setup variables for completion. Need to obtain "line" again,
3516 * it may have become invalid. */
3517 line = ml_get(curwin->w_cursor.lnum);
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003518 compl_length = curs_col - compl_col;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003519 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3520 if (compl_pattern == NULL)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00003521 return FAIL;
3522 }
3523#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003524 else if (ctrl_x_mode == CTRL_X_OCCULT)
3525 {
3526 /* TODO: let language-specific function handle locating the text
Bram Moolenaar5a8684e2005-07-30 22:43:24 +00003527 * to be completed. */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003528 while (--startcol >= 0 && vim_isIDc(line[startcol]))
3529 ;
3530 compl_col += ++startcol;
3531 compl_length = (int)curs_col - startcol;
3532 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3533 if (compl_pattern == NULL)
3534 return FAIL;
3535 }
Bram Moolenaar488c6512005-08-11 20:09:58 +00003536 else if (ctrl_x_mode == CTRL_X_SPELL)
3537 {
3538#ifdef FEAT_SYN_HL
3539 compl_col = spell_word_start(startcol);
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003540 if (compl_col == (colnr_T)startcol)
Bram Moolenaar488c6512005-08-11 20:09:58 +00003541 return FAIL;
3542 compl_length = (int)curs_col - compl_col;
3543 compl_pattern = vim_strnsave(line + compl_col, compl_length);
3544 if (compl_pattern == NULL)
3545#endif
3546 return FAIL;
3547 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003548 else
3549 {
3550 EMSG2(_(e_intern2), "ins_complete()");
3551 return FAIL;
3552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003554 if (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 {
3556 edit_submode_pre = (char_u *)_(" Adding");
3557 if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
3558 {
3559 /* Insert a new line, keep indentation but ignore 'comments' */
3560#ifdef FEAT_COMMENTS
3561 char_u *old = curbuf->b_p_com;
3562
3563 curbuf->b_p_com = (char_u *)"";
3564#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003565 compl_startpos.lnum = curwin->w_cursor.lnum;
3566 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 ins_eol('\r');
3568#ifdef FEAT_COMMENTS
3569 curbuf->b_p_com = old;
3570#endif
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003571 compl_length = 0;
3572 compl_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 }
3574 }
3575 else
3576 {
3577 edit_submode_pre = NULL;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003578 compl_startpos.col = compl_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579 }
3580
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003581 if (compl_cont_status & CONT_LOCAL)
3582 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 else
3584 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
3585
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 /* Always add completion for the original text. Note that
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003587 * "compl_orig_text" itself (not a copy) is added, it will be freed
3588 * when the list of matches is freed. */
3589 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
3590 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
3591 -1, NULL, 0, ORIGINAL_TEXT) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003593 vim_free(compl_pattern);
3594 compl_pattern = NULL;
3595 vim_free(compl_orig_text);
3596 compl_orig_text = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 return FAIL;
3598 }
3599
3600 /* showmode might reset the internal line pointers, so it must
3601 * be called before line = ml_get(), or when this address is no
3602 * longer needed. -- Acevedo.
3603 */
3604 edit_submode_extra = (char_u *)_("-- Searching...");
3605 edit_submode_highl = HLF_COUNT;
3606 showmode();
3607 edit_submode_extra = NULL;
3608 out_flush();
3609 }
3610
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003611 compl_shown_match = compl_curr_match;
3612 compl_shows_dir = compl_direction;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613
3614 /*
3615 * Find next match.
3616 */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003617 n = ins_compl_next(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003619 if (n > 1) /* all matches have been found */
3620 compl_matches = n;
3621 compl_curr_match = compl_shown_match;
3622 compl_direction = compl_shows_dir;
3623 compl_interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624
3625 /* eat the ESC to avoid leaving insert mode */
3626 if (got_int && !global_busy)
3627 {
3628 (void)vgetc();
3629 got_int = FALSE;
3630 }
3631
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003632 /* we found no match if the list has only the "compl_orig_text"-entry */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003633 if (compl_first_match == compl_first_match->cp_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003635 edit_submode_extra = (compl_cont_status & CONT_ADDING)
3636 && compl_length > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
3638 edit_submode_highl = HLF_E;
3639 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
3640 * because we couldn't expand anything at first place, but if we used
3641 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
3642 * (such as M in M'exico) if not tried already. -- Acevedo */
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003643 if ( compl_length > 1
3644 || (compl_cont_status & CONT_ADDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645 || (ctrl_x_mode != 0
3646 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
3647 && ctrl_x_mode != CTRL_X_PATH_DEFINES))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003648 compl_cont_status &= ~CONT_N_ADDS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649 }
3650
Bram Moolenaar572cb562005-08-05 21:35:02 +00003651 if (compl_curr_match->cp_flags & CONT_S_IPOS)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003652 compl_cont_status |= CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003654 compl_cont_status &= ~CONT_S_IPOS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655
3656 if (edit_submode_extra == NULL)
3657 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003658 if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 {
3660 edit_submode_extra = (char_u *)_("Back at original");
3661 edit_submode_highl = HLF_W;
3662 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003663 else if (compl_cont_status & CONT_S_IPOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 {
3665 edit_submode_extra = (char_u *)_("Word from other line");
3666 edit_submode_highl = HLF_COUNT;
3667 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00003668 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 {
3670 edit_submode_extra = (char_u *)_("The only match");
3671 edit_submode_highl = HLF_COUNT;
3672 }
3673 else
3674 {
3675 /* Update completion sequence number when needed. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003676 if (compl_curr_match->cp_number == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003678 int number = 0;
3679 compl_T *match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003681 if (compl_direction == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 {
3683 /* search backwards for the first valid (!= -1) number.
3684 * This should normally succeed already at the first loop
3685 * cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003686 for (match = compl_curr_match->cp_prev; match != NULL
3687 && match != compl_first_match;
3688 match = match->cp_prev)
3689 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003691 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 break;
3693 }
3694 if (match != NULL)
3695 /* go up and assign all numbers which are not assigned
3696 * yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003697 for (match = match->cp_next; match
3698 && match->cp_number == -1;
3699 match = match->cp_next)
3700 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 }
3702 else /* BACKWARD */
3703 {
3704 /* search forwards (upwards) for the first valid (!= -1)
3705 * number. This should normally succeed already at the
3706 * first loop cycle, so it's fast! */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003707 for (match = compl_curr_match->cp_next; match != NULL
3708 && match != compl_first_match;
3709 match = match->cp_next)
3710 if (match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 {
Bram Moolenaar572cb562005-08-05 21:35:02 +00003712 number = match->cp_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 break;
3714 }
3715 if (match != NULL)
3716 /* go down and assign all numbers which are not
3717 * assigned yet */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003718 for (match = match->cp_prev; match
3719 && match->cp_number == -1;
3720 match = match->cp_prev)
3721 match->cp_number = ++number;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 }
3723 }
3724
3725 /* The match should always have a sequnce number now, this is just
3726 * a safety check. */
Bram Moolenaar572cb562005-08-05 21:35:02 +00003727 if (compl_curr_match->cp_number != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728 {
3729 /* Space for 10 text chars. + 2x10-digit no.s */
3730 static char_u match_ref[31];
3731
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003732 if (compl_matches > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 sprintf((char *)IObuff, _("match %d of %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00003734 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00003736 sprintf((char *)IObuff, _("match %d"),
Bram Moolenaar572cb562005-08-05 21:35:02 +00003737 compl_curr_match->cp_number);
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003738 vim_strncpy(match_ref, IObuff, 30);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 edit_submode_extra = match_ref;
3740 edit_submode_highl = HLF_R;
3741 if (dollar_vcol)
3742 curs_columns(FALSE);
3743 }
3744 }
3745 }
3746
3747 /* Show a message about what (completion) mode we're in. */
3748 showmode();
3749 if (edit_submode_extra != NULL)
3750 {
3751 if (!p_smd)
3752 msg_attr(edit_submode_extra,
3753 edit_submode_highl < HLF_COUNT
3754 ? hl_attr(edit_submode_highl) : 0);
3755 }
3756 else
3757 msg_clr_cmdline(); /* necessary for "noshowmode" */
3758
3759 return OK;
3760}
3761
3762/*
3763 * Looks in the first "len" chars. of "src" for search-metachars.
3764 * If dest is not NULL the chars. are copied there quoting (with
3765 * a backslash) the metachars, and dest would be NUL terminated.
3766 * Returns the length (needed) of dest
3767 */
3768 static int
3769quote_meta(dest, src, len)
3770 char_u *dest;
3771 char_u *src;
3772 int len;
3773{
3774 int m;
3775
3776 for (m = len; --len >= 0; src++)
3777 {
3778 switch (*src)
3779 {
3780 case '.':
3781 case '*':
3782 case '[':
3783 if (ctrl_x_mode == CTRL_X_DICTIONARY
3784 || ctrl_x_mode == CTRL_X_THESAURUS)
3785 break;
3786 case '~':
3787 if (!p_magic) /* quote these only if magic is set */
3788 break;
3789 case '\\':
3790 if (ctrl_x_mode == CTRL_X_DICTIONARY
3791 || ctrl_x_mode == CTRL_X_THESAURUS)
3792 break;
3793 case '^': /* currently it's not needed. */
3794 case '$':
3795 m++;
3796 if (dest != NULL)
3797 *dest++ = '\\';
3798 break;
3799 }
3800 if (dest != NULL)
3801 *dest++ = *src;
Bram Moolenaar572cb562005-08-05 21:35:02 +00003802# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803 /* Copy remaining bytes of a multibyte character. */
3804 if (has_mbyte)
3805 {
3806 int i, mb_len;
3807
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003808 mb_len = (*mb_ptr2len)(src) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809 if (mb_len > 0 && len >= mb_len)
3810 for (i = 0; i < mb_len; ++i)
3811 {
3812 --len;
3813 ++src;
3814 if (dest != NULL)
3815 *dest++ = *src;
3816 }
3817 }
Bram Moolenaar572cb562005-08-05 21:35:02 +00003818# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 }
3820 if (dest != NULL)
3821 *dest = NUL;
3822
3823 return m;
3824}
3825#endif /* FEAT_INS_EXPAND */
3826
3827/*
3828 * Next character is interpreted literally.
3829 * A one, two or three digit decimal number is interpreted as its byte value.
3830 * If one or two digits are entered, the next character is given to vungetc().
3831 * For Unicode a character > 255 may be returned.
3832 */
3833 int
3834get_literal()
3835{
3836 int cc;
3837 int nc;
3838 int i;
3839 int hex = FALSE;
3840 int octal = FALSE;
3841#ifdef FEAT_MBYTE
3842 int unicode = 0;
3843#endif
3844
3845 if (got_int)
3846 return Ctrl_C;
3847
3848#ifdef FEAT_GUI
3849 /*
3850 * In GUI there is no point inserting the internal code for a special key.
3851 * It is more useful to insert the string "<KEY>" instead. This would
3852 * probably be useful in a text window too, but it would not be
3853 * vi-compatible (maybe there should be an option for it?) -- webb
3854 */
3855 if (gui.in_use)
3856 ++allow_keys;
3857#endif
3858#ifdef USE_ON_FLY_SCROLL
3859 dont_scroll = TRUE; /* disallow scrolling here */
3860#endif
3861 ++no_mapping; /* don't map the next key hits */
3862 cc = 0;
3863 i = 0;
3864 for (;;)
3865 {
3866 do
3867 nc = safe_vgetc();
3868 while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
3869 || nc == K_HOR_SCROLLBAR);
3870#ifdef FEAT_CMDL_INFO
3871 if (!(State & CMDLINE)
3872# ifdef FEAT_MBYTE
3873 && MB_BYTE2LEN_CHECK(nc) == 1
3874# endif
3875 )
3876 add_to_showcmd(nc);
3877#endif
3878 if (nc == 'x' || nc == 'X')
3879 hex = TRUE;
3880 else if (nc == 'o' || nc == 'O')
3881 octal = TRUE;
3882#ifdef FEAT_MBYTE
3883 else if (nc == 'u' || nc == 'U')
3884 unicode = nc;
3885#endif
3886 else
3887 {
3888 if (hex
3889#ifdef FEAT_MBYTE
3890 || unicode != 0
3891#endif
3892 )
3893 {
3894 if (!vim_isxdigit(nc))
3895 break;
3896 cc = cc * 16 + hex2nr(nc);
3897 }
3898 else if (octal)
3899 {
3900 if (nc < '0' || nc > '7')
3901 break;
3902 cc = cc * 8 + nc - '0';
3903 }
3904 else
3905 {
3906 if (!VIM_ISDIGIT(nc))
3907 break;
3908 cc = cc * 10 + nc - '0';
3909 }
3910
3911 ++i;
3912 }
3913
3914 if (cc > 255
3915#ifdef FEAT_MBYTE
3916 && unicode == 0
3917#endif
3918 )
3919 cc = 255; /* limit range to 0-255 */
3920 nc = 0;
3921
3922 if (hex) /* hex: up to two chars */
3923 {
3924 if (i >= 2)
3925 break;
3926 }
3927#ifdef FEAT_MBYTE
3928 else if (unicode) /* Unicode: up to four or eight chars */
3929 {
3930 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
3931 break;
3932 }
3933#endif
3934 else if (i >= 3) /* decimal or octal: up to three chars */
3935 break;
3936 }
3937 if (i == 0) /* no number entered */
3938 {
3939 if (nc == K_ZERO) /* NUL is stored as NL */
3940 {
3941 cc = '\n';
3942 nc = 0;
3943 }
3944 else
3945 {
3946 cc = nc;
3947 nc = 0;
3948 }
3949 }
3950
3951 if (cc == 0) /* NUL is stored as NL */
3952 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00003953#ifdef FEAT_MBYTE
3954 if (enc_dbcs && (cc & 0xff) == 0)
3955 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
3956 second byte will cause trouble! */
3957#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958
3959 --no_mapping;
3960#ifdef FEAT_GUI
3961 if (gui.in_use)
3962 --allow_keys;
3963#endif
3964 if (nc)
3965 vungetc(nc);
3966 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
3967 return cc;
3968}
3969
3970/*
3971 * Insert character, taking care of special keys and mod_mask
3972 */
3973 static void
3974insert_special(c, allow_modmask, ctrlv)
3975 int c;
3976 int allow_modmask;
3977 int ctrlv; /* c was typed after CTRL-V */
3978{
3979 char_u *p;
3980 int len;
3981
3982 /*
3983 * Special function key, translate into "<Key>". Up to the last '>' is
3984 * inserted with ins_str(), so as not to replace characters in replace
3985 * mode.
3986 * Only use mod_mask for special keys, to avoid things like <S-Space>,
3987 * unless 'allow_modmask' is TRUE.
3988 */
3989#ifdef MACOS
3990 /* Command-key never produces a normal key */
3991 if (mod_mask & MOD_MASK_CMD)
3992 allow_modmask = TRUE;
3993#endif
3994 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
3995 {
3996 p = get_special_key_name(c, mod_mask);
3997 len = (int)STRLEN(p);
3998 c = p[len - 1];
3999 if (len > 2)
4000 {
4001 if (stop_arrow() == FAIL)
4002 return;
4003 p[len - 1] = NUL;
4004 ins_str(p);
4005 AppendToRedobuffLit(p);
4006 ctrlv = FALSE;
4007 }
4008 }
4009 if (stop_arrow() == OK)
4010 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
4011}
4012
4013/*
4014 * Special characters in this context are those that need processing other
4015 * than the simple insertion that can be performed here. This includes ESC
4016 * which terminates the insert, and CR/NL which need special processing to
4017 * open up a new line. This routine tries to optimize insertions performed by
4018 * the "redo", "undo" or "put" commands, so it needs to know when it should
4019 * stop and defer processing to the "normal" mechanism.
4020 * '0' and '^' are special, because they can be followed by CTRL-D.
4021 */
4022#ifdef EBCDIC
4023# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
4024#else
4025# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
4026#endif
4027
4028#ifdef FEAT_MBYTE
4029# define WHITECHAR(cc) (vim_iswhite(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
4030#else
4031# define WHITECHAR(cc) vim_iswhite(cc)
4032#endif
4033
4034 void
4035insertchar(c, flags, second_indent)
4036 int c; /* character to insert or NUL */
4037 int flags; /* INSCHAR_FORMAT, etc. */
4038 int second_indent; /* indent for second line if >= 0 */
4039{
4040 int haveto_redraw = FALSE;
4041 int textwidth;
4042#ifdef FEAT_COMMENTS
4043 colnr_T leader_len;
4044 char_u *p;
4045 int no_leader = FALSE;
4046 int do_comments = (flags & INSCHAR_DO_COM);
4047#endif
4048 int fo_white_par;
4049 int first_line = TRUE;
4050 int fo_ins_blank;
4051#ifdef FEAT_MBYTE
4052 int fo_multibyte;
4053#endif
4054 int save_char = NUL;
4055 int cc;
4056
4057 textwidth = comp_textwidth(flags & INSCHAR_FORMAT);
4058 fo_ins_blank = has_format_option(FO_INS_BLANK);
4059#ifdef FEAT_MBYTE
4060 fo_multibyte = has_format_option(FO_MBYTE_BREAK);
4061#endif
4062 fo_white_par = has_format_option(FO_WHITE_PAR);
4063
4064 /*
4065 * Try to break the line in two or more pieces when:
4066 * - Always do this if we have been called to do formatting only.
4067 * - Always do this when 'formatoptions' has the 'a' flag and the line
4068 * ends in white space.
4069 * - Otherwise:
4070 * - Don't do this if inserting a blank
4071 * - Don't do this if an existing character is being replaced, unless
4072 * we're in VREPLACE mode.
4073 * - Do this if the cursor is not on the line where insert started
4074 * or - 'formatoptions' doesn't have 'l' or the line was not too long
4075 * before the insert.
4076 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
4077 * before 'textwidth'
4078 */
4079 if (textwidth
4080 && ((flags & INSCHAR_FORMAT)
4081 || (!vim_iswhite(c)
4082 && !((State & REPLACE_FLAG)
4083#ifdef FEAT_VREPLACE
4084 && !(State & VREPLACE_FLAG)
4085#endif
4086 && *ml_get_cursor() != NUL)
4087 && (curwin->w_cursor.lnum != Insstart.lnum
4088 || ((!has_format_option(FO_INS_LONG)
4089 || Insstart_textlen <= (colnr_T)textwidth)
4090 && (!fo_ins_blank
4091 || Insstart_blank_vcol <= (colnr_T)textwidth
4092 ))))))
4093 {
4094 /*
4095 * When 'ai' is off we don't want a space under the cursor to be
4096 * deleted. Replace it with an 'x' temporarily.
4097 */
4098 if (!curbuf->b_p_ai)
4099 {
4100 cc = gchar_cursor();
4101 if (vim_iswhite(cc))
4102 {
4103 save_char = cc;
4104 pchar_cursor('x');
4105 }
4106 }
4107
4108 /*
4109 * Repeat breaking lines, until the current line is not too long.
4110 */
4111 while (!got_int)
4112 {
4113 int startcol; /* Cursor column at entry */
4114 int wantcol; /* column at textwidth border */
4115 int foundcol; /* column for start of spaces */
4116 int end_foundcol = 0; /* column for start of word */
4117 colnr_T len;
4118 colnr_T virtcol;
4119#ifdef FEAT_VREPLACE
4120 int orig_col = 0;
4121 char_u *saved_text = NULL;
4122#endif
4123 colnr_T col;
4124
4125 virtcol = get_nolist_virtcol();
4126 if (virtcol < (colnr_T)textwidth)
4127 break;
4128
4129#ifdef FEAT_COMMENTS
4130 if (no_leader)
4131 do_comments = FALSE;
4132 else if (!(flags & INSCHAR_FORMAT)
4133 && has_format_option(FO_WRAP_COMS))
4134 do_comments = TRUE;
4135
4136 /* Don't break until after the comment leader */
4137 if (do_comments)
4138 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE);
4139 else
4140 leader_len = 0;
4141
4142 /* If the line doesn't start with a comment leader, then don't
4143 * start one in a following broken line. Avoids that a %word
4144 * moved to the start of the next line causes all following lines
4145 * to start with %. */
4146 if (leader_len == 0)
4147 no_leader = TRUE;
4148#endif
4149 if (!(flags & INSCHAR_FORMAT)
4150#ifdef FEAT_COMMENTS
4151 && leader_len == 0
4152#endif
4153 && !has_format_option(FO_WRAP))
4154
4155 {
4156 textwidth = 0;
4157 break;
4158 }
4159 if ((startcol = curwin->w_cursor.col) == 0)
4160 break;
4161
4162 /* find column of textwidth border */
4163 coladvance((colnr_T)textwidth);
4164 wantcol = curwin->w_cursor.col;
4165
4166 curwin->w_cursor.col = startcol - 1;
4167#ifdef FEAT_MBYTE
4168 /* Correct cursor for multi-byte character. */
4169 if (has_mbyte)
4170 mb_adjust_cursor();
4171#endif
4172 foundcol = 0;
4173
4174 /*
4175 * Find position to break at.
4176 * Stop at first entered white when 'formatoptions' has 'v'
4177 */
4178 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
4179 || curwin->w_cursor.lnum != Insstart.lnum
4180 || curwin->w_cursor.col >= Insstart.col)
4181 {
4182 cc = gchar_cursor();
4183 if (WHITECHAR(cc))
4184 {
4185 /* remember position of blank just before text */
4186 end_foundcol = curwin->w_cursor.col;
4187
4188 /* find start of sequence of blanks */
4189 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
4190 {
4191 dec_cursor();
4192 cc = gchar_cursor();
4193 }
4194 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
4195 break; /* only spaces in front of text */
4196#ifdef FEAT_COMMENTS
4197 /* Don't break until after the comment leader */
4198 if (curwin->w_cursor.col < leader_len)
4199 break;
4200#endif
4201 if (has_format_option(FO_ONE_LETTER))
4202 {
4203 /* do not break after one-letter words */
4204 if (curwin->w_cursor.col == 0)
4205 break; /* one-letter word at begin */
4206
4207 col = curwin->w_cursor.col;
4208 dec_cursor();
4209 cc = gchar_cursor();
4210
4211 if (WHITECHAR(cc))
4212 continue; /* one-letter, continue */
4213 curwin->w_cursor.col = col;
4214 }
4215#ifdef FEAT_MBYTE
4216 if (has_mbyte)
4217 foundcol = curwin->w_cursor.col
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004218 + (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 else
4220#endif
4221 foundcol = curwin->w_cursor.col + 1;
4222 if (curwin->w_cursor.col < (colnr_T)wantcol)
4223 break;
4224 }
4225#ifdef FEAT_MBYTE
4226 else if (cc >= 0x100 && fo_multibyte
4227 && curwin->w_cursor.col <= (colnr_T)wantcol)
4228 {
4229 /* Break after or before a multi-byte character. */
4230 foundcol = curwin->w_cursor.col;
4231 if (curwin->w_cursor.col < (colnr_T)wantcol)
4232 foundcol += (*mb_char2len)(cc);
4233 end_foundcol = foundcol;
4234 break;
4235 }
4236#endif
4237 if (curwin->w_cursor.col == 0)
4238 break;
4239 dec_cursor();
4240 }
4241
4242 if (foundcol == 0) /* no spaces, cannot break line */
4243 {
4244 curwin->w_cursor.col = startcol;
4245 break;
4246 }
4247
4248 /* Going to break the line, remove any "$" now. */
4249 undisplay_dollar();
4250
4251 /*
4252 * Offset between cursor position and line break is used by replace
4253 * stack functions. VREPLACE does not use this, and backspaces
4254 * over the text instead.
4255 */
4256#ifdef FEAT_VREPLACE
4257 if (State & VREPLACE_FLAG)
4258 orig_col = startcol; /* Will start backspacing from here */
4259 else
4260#endif
4261 replace_offset = startcol - end_foundcol - 1;
4262
4263 /*
4264 * adjust startcol for spaces that will be deleted and
4265 * characters that will remain on top line
4266 */
4267 curwin->w_cursor.col = foundcol;
4268 while (cc = gchar_cursor(), WHITECHAR(cc))
4269 inc_cursor();
4270 startcol -= curwin->w_cursor.col;
4271 if (startcol < 0)
4272 startcol = 0;
4273
4274#ifdef FEAT_VREPLACE
4275 if (State & VREPLACE_FLAG)
4276 {
4277 /*
4278 * In VREPLACE mode, we will backspace over the text to be
4279 * wrapped, so save a copy now to put on the next line.
4280 */
4281 saved_text = vim_strsave(ml_get_cursor());
4282 curwin->w_cursor.col = orig_col;
4283 if (saved_text == NULL)
4284 break; /* Can't do it, out of memory */
4285 saved_text[startcol] = NUL;
4286
4287 /* Backspace over characters that will move to the next line */
4288 if (!fo_white_par)
4289 backspace_until_column(foundcol);
4290 }
4291 else
4292#endif
4293 {
4294 /* put cursor after pos. to break line */
4295 if (!fo_white_par)
4296 curwin->w_cursor.col = foundcol;
4297 }
4298
4299 /*
4300 * Split the line just before the margin.
4301 * Only insert/delete lines, but don't really redraw the window.
4302 */
4303 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
4304 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
4305#ifdef FEAT_COMMENTS
4306 + (do_comments ? OPENLINE_DO_COM : 0)
4307#endif
4308 , old_indent);
4309 old_indent = 0;
4310
4311 replace_offset = 0;
4312 if (first_line)
4313 {
4314 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
4315 second_indent = get_number_indent(curwin->w_cursor.lnum -1);
4316 if (second_indent >= 0)
4317 {
4318#ifdef FEAT_VREPLACE
4319 if (State & VREPLACE_FLAG)
4320 change_indent(INDENT_SET, second_indent, FALSE, NUL);
4321 else
4322#endif
4323 (void)set_indent(second_indent, SIN_CHANGED);
4324 }
4325 first_line = FALSE;
4326 }
4327
4328#ifdef FEAT_VREPLACE
4329 if (State & VREPLACE_FLAG)
4330 {
4331 /*
4332 * In VREPLACE mode we have backspaced over the text to be
4333 * moved, now we re-insert it into the new line.
4334 */
4335 ins_bytes(saved_text);
4336 vim_free(saved_text);
4337 }
4338 else
4339#endif
4340 {
4341 /*
4342 * Check if cursor is not past the NUL off the line, cindent
4343 * may have added or removed indent.
4344 */
4345 curwin->w_cursor.col += startcol;
4346 len = (colnr_T)STRLEN(ml_get_curline());
4347 if (curwin->w_cursor.col > len)
4348 curwin->w_cursor.col = len;
4349 }
4350
4351 haveto_redraw = TRUE;
4352#ifdef FEAT_CINDENT
4353 can_cindent = TRUE;
4354#endif
4355 /* moved the cursor, don't autoindent or cindent now */
4356 did_ai = FALSE;
4357#ifdef FEAT_SMARTINDENT
4358 did_si = FALSE;
4359 can_si = FALSE;
4360 can_si_back = FALSE;
4361#endif
4362 line_breakcheck();
4363 }
4364
4365 if (save_char) /* put back space after cursor */
4366 pchar_cursor(save_char);
4367
4368 if (c == NUL) /* formatting only */
4369 return;
4370 if (haveto_redraw)
4371 {
4372 update_topline();
4373 redraw_curbuf_later(VALID);
4374 }
4375 }
4376 if (c == NUL) /* only formatting was wanted */
4377 return;
4378
4379#ifdef FEAT_COMMENTS
4380 /* Check whether this character should end a comment. */
4381 if (did_ai && (int)c == end_comment_pending)
4382 {
4383 char_u *line;
4384 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
4385 int middle_len, end_len;
4386 int i;
4387
4388 /*
4389 * Need to remove existing (middle) comment leader and insert end
4390 * comment leader. First, check what comment leader we can find.
4391 */
4392 i = get_leader_len(line = ml_get_curline(), &p, FALSE);
4393 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
4394 {
4395 /* Skip middle-comment string */
4396 while (*p && p[-1] != ':') /* find end of middle flags */
4397 ++p;
4398 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
4399 /* Don't count trailing white space for middle_len */
4400 while (middle_len > 0 && vim_iswhite(lead_end[middle_len - 1]))
4401 --middle_len;
4402
4403 /* Find the end-comment string */
4404 while (*p && p[-1] != ':') /* find end of end flags */
4405 ++p;
4406 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
4407
4408 /* Skip white space before the cursor */
4409 i = curwin->w_cursor.col;
4410 while (--i >= 0 && vim_iswhite(line[i]))
4411 ;
4412 i++;
4413
4414 /* Skip to before the middle leader */
4415 i -= middle_len;
4416
4417 /* Check some expected things before we go on */
4418 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
4419 {
4420 /* Backspace over all the stuff we want to replace */
4421 backspace_until_column(i);
4422
4423 /*
4424 * Insert the end-comment string, except for the last
4425 * character, which will get inserted as normal later.
4426 */
4427 ins_bytes_len(lead_end, end_len - 1);
4428 }
4429 }
4430 }
4431 end_comment_pending = NUL;
4432#endif
4433
4434 did_ai = FALSE;
4435#ifdef FEAT_SMARTINDENT
4436 did_si = FALSE;
4437 can_si = FALSE;
4438 can_si_back = FALSE;
4439#endif
4440
4441 /*
4442 * If there's any pending input, grab up to INPUT_BUFLEN at once.
4443 * This speeds up normal text input considerably.
4444 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
4445 * need to re-indent at a ':', or any other character (but not what
4446 * 'paste' is set)..
4447 */
4448#ifdef USE_ON_FLY_SCROLL
4449 dont_scroll = FALSE; /* allow scrolling here */
4450#endif
4451
4452 if ( !ISSPECIAL(c)
4453#ifdef FEAT_MBYTE
4454 && (!has_mbyte || (*mb_char2len)(c) == 1)
4455#endif
4456 && vpeekc() != NUL
4457 && !(State & REPLACE_FLAG)
4458#ifdef FEAT_CINDENT
4459 && !cindent_on()
4460#endif
4461#ifdef FEAT_RIGHTLEFT
4462 && !p_ri
4463#endif
4464 )
4465 {
4466#define INPUT_BUFLEN 100
4467 char_u buf[INPUT_BUFLEN + 1];
4468 int i;
4469 colnr_T virtcol = 0;
4470
4471 buf[0] = c;
4472 i = 1;
4473 if (textwidth)
4474 virtcol = get_nolist_virtcol();
4475 /*
4476 * Stop the string when:
4477 * - no more chars available
4478 * - finding a special character (command key)
4479 * - buffer is full
4480 * - running into the 'textwidth' boundary
4481 * - need to check for abbreviation: A non-word char after a word-char
4482 */
4483 while ( (c = vpeekc()) != NUL
4484 && !ISSPECIAL(c)
4485#ifdef FEAT_MBYTE
4486 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
4487#endif
4488 && i < INPUT_BUFLEN
4489 && (textwidth == 0
4490 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
4491 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
4492 {
4493#ifdef FEAT_RIGHTLEFT
4494 c = vgetc();
4495 if (p_hkmap && KeyTyped)
4496 c = hkmap(c); /* Hebrew mode mapping */
4497# ifdef FEAT_FKMAP
4498 if (p_fkmap && KeyTyped)
4499 c = fkmap(c); /* Farsi mode mapping */
4500# endif
4501 buf[i++] = c;
4502#else
4503 buf[i++] = vgetc();
4504#endif
4505 }
4506
4507#ifdef FEAT_DIGRAPHS
4508 do_digraph(-1); /* clear digraphs */
4509 do_digraph(buf[i-1]); /* may be the start of a digraph */
4510#endif
4511 buf[i] = NUL;
4512 ins_str(buf);
4513 if (flags & INSCHAR_CTRLV)
4514 {
4515 redo_literal(*buf);
4516 i = 1;
4517 }
4518 else
4519 i = 0;
4520 if (buf[i] != NUL)
4521 AppendToRedobuffLit(buf + i);
4522 }
4523 else
4524 {
4525#ifdef FEAT_MBYTE
4526 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
4527 {
4528 char_u buf[MB_MAXBYTES + 1];
4529
4530 (*mb_char2bytes)(c, buf);
4531 buf[cc] = NUL;
4532 ins_char_bytes(buf, cc);
4533 AppendCharToRedobuff(c);
4534 }
4535 else
4536#endif
4537 {
4538 ins_char(c);
4539 if (flags & INSCHAR_CTRLV)
4540 redo_literal(c);
4541 else
4542 AppendCharToRedobuff(c);
4543 }
4544 }
4545}
4546
4547/*
4548 * Called after inserting or deleting text: When 'formatoptions' includes the
4549 * 'a' flag format from the current line until the end of the paragraph.
4550 * Keep the cursor at the same position relative to the text.
4551 * The caller must have saved the cursor line for undo, following ones will be
4552 * saved here.
4553 */
4554 void
4555auto_format(trailblank, prev_line)
4556 int trailblank; /* when TRUE also format with trailing blank */
4557 int prev_line; /* may start in previous line */
4558{
4559 pos_T pos;
4560 colnr_T len;
4561 char_u *old;
4562 char_u *new, *pnew;
4563 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004564 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565
4566 if (!has_format_option(FO_AUTO))
4567 return;
4568
4569 pos = curwin->w_cursor;
4570 old = ml_get_curline();
4571
4572 /* may remove added space */
4573 check_auto_format(FALSE);
4574
4575 /* Don't format in Insert mode when the cursor is on a trailing blank, the
4576 * user might insert normal text next. Also skip formatting when "1" is
4577 * in 'formatoptions' and there is a single character before the cursor.
4578 * Otherwise the line would be broken and when typing another non-white
4579 * next they are not joined back together. */
4580 wasatend = (pos.col == STRLEN(old));
4581 if (*old != NUL && !trailblank && wasatend)
4582 {
4583 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004584 cc = gchar_cursor();
4585 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
4586 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004588 cc = gchar_cursor();
4589 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 {
4591 curwin->w_cursor = pos;
4592 return;
4593 }
4594 curwin->w_cursor = pos;
4595 }
4596
4597#ifdef FEAT_COMMENTS
4598 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
4599 * comments. */
4600 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
4601 && get_leader_len(old, NULL, FALSE) == 0)
4602 return;
4603#endif
4604
4605 /*
4606 * May start formatting in a previous line, so that after "x" a word is
4607 * moved to the previous line if it fits there now. Only when this is not
4608 * the start of a paragraph.
4609 */
4610 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
4611 {
4612 --curwin->w_cursor.lnum;
4613 if (u_save_cursor() == FAIL)
4614 return;
4615 }
4616
4617 /*
4618 * Do the formatting and restore the cursor position. "saved_cursor" will
4619 * be adjusted for the text formatting.
4620 */
4621 saved_cursor = pos;
4622 format_lines((linenr_T)-1);
4623 curwin->w_cursor = saved_cursor;
4624 saved_cursor.lnum = 0;
4625
4626 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
4627 {
4628 /* "cannot happen" */
4629 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4630 coladvance((colnr_T)MAXCOL);
4631 }
4632 else
4633 check_cursor_col();
4634
4635 /* Insert mode: If the cursor is now after the end of the line while it
4636 * previously wasn't, the line was broken. Because of the rule above we
4637 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
4638 * formatted. */
4639 if (!wasatend && has_format_option(FO_WHITE_PAR))
4640 {
4641 new = ml_get_curline();
4642 len = STRLEN(new);
4643 if (curwin->w_cursor.col == len)
4644 {
4645 pnew = vim_strnsave(new, len + 2);
4646 pnew[len] = ' ';
4647 pnew[len + 1] = NUL;
4648 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
4649 /* remove the space later */
4650 did_add_space = TRUE;
4651 }
4652 else
4653 /* may remove added space */
4654 check_auto_format(FALSE);
4655 }
4656
4657 check_cursor();
4658}
4659
4660/*
4661 * When an extra space was added to continue a paragraph for auto-formatting,
4662 * delete it now. The space must be under the cursor, just after the insert
4663 * position.
4664 */
4665 static void
4666check_auto_format(end_insert)
4667 int end_insert; /* TRUE when ending Insert mode */
4668{
4669 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004670 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671
4672 if (did_add_space)
4673 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00004674 cc = gchar_cursor();
4675 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 /* Somehow the space was removed already. */
4677 did_add_space = FALSE;
4678 else
4679 {
4680 if (!end_insert)
4681 {
4682 inc_cursor();
4683 c = gchar_cursor();
4684 dec_cursor();
4685 }
4686 if (c != NUL)
4687 {
4688 /* The space is no longer at the end of the line, delete it. */
4689 del_char(FALSE);
4690 did_add_space = FALSE;
4691 }
4692 }
4693 }
4694}
4695
4696/*
4697 * Find out textwidth to be used for formatting:
4698 * if 'textwidth' option is set, use it
4699 * else if 'wrapmargin' option is set, use W_WIDTH(curwin) - 'wrapmargin'
4700 * if invalid value, use 0.
4701 * Set default to window width (maximum 79) for "gq" operator.
4702 */
4703 int
4704comp_textwidth(ff)
4705 int ff; /* force formatting (for "Q" command) */
4706{
4707 int textwidth;
4708
4709 textwidth = curbuf->b_p_tw;
4710 if (textwidth == 0 && curbuf->b_p_wm)
4711 {
4712 /* The width is the window width minus 'wrapmargin' minus all the
4713 * things that add to the margin. */
4714 textwidth = W_WIDTH(curwin) - curbuf->b_p_wm;
4715#ifdef FEAT_CMDWIN
4716 if (cmdwin_type != 0)
4717 textwidth -= 1;
4718#endif
4719#ifdef FEAT_FOLDING
4720 textwidth -= curwin->w_p_fdc;
4721#endif
4722#ifdef FEAT_SIGNS
4723 if (curwin->w_buffer->b_signlist != NULL
4724# ifdef FEAT_NETBEANS_INTG
4725 || usingNetbeans
4726# endif
4727 )
4728 textwidth -= 1;
4729#endif
4730 if (curwin->w_p_nu)
4731 textwidth -= 8;
4732 }
4733 if (textwidth < 0)
4734 textwidth = 0;
4735 if (ff && textwidth == 0)
4736 {
4737 textwidth = W_WIDTH(curwin) - 1;
4738 if (textwidth > 79)
4739 textwidth = 79;
4740 }
4741 return textwidth;
4742}
4743
4744/*
4745 * Put a character in the redo buffer, for when just after a CTRL-V.
4746 */
4747 static void
4748redo_literal(c)
4749 int c;
4750{
4751 char_u buf[10];
4752
4753 /* Only digits need special treatment. Translate them into a string of
4754 * three digits. */
4755 if (VIM_ISDIGIT(c))
4756 {
4757 sprintf((char *)buf, "%03d", c);
4758 AppendToRedobuff(buf);
4759 }
4760 else
4761 AppendCharToRedobuff(c);
4762}
4763
4764/*
4765 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00004766 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767 */
4768 static void
4769start_arrow(end_insert_pos)
4770 pos_T *end_insert_pos;
4771{
4772 if (!arrow_used) /* something has been inserted */
4773 {
4774 AppendToRedobuff(ESC_STR);
4775 stop_insert(end_insert_pos, FALSE);
4776 arrow_used = TRUE; /* this means we stopped the current insert */
4777 }
Bram Moolenaar217ad922005-03-20 22:37:15 +00004778#ifdef FEAT_SYN_HL
4779 check_spell_redraw();
4780#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781}
4782
Bram Moolenaar217ad922005-03-20 22:37:15 +00004783#ifdef FEAT_SYN_HL
4784/*
4785 * If we skipped highlighting word at cursor, do it now.
4786 * It may be skipped again, thus reset spell_redraw_lnum first.
4787 */
4788 static void
4789check_spell_redraw()
4790{
4791 if (spell_redraw_lnum != 0)
4792 {
4793 linenr_T lnum = spell_redraw_lnum;
4794
4795 spell_redraw_lnum = 0;
4796 redrawWinline(lnum, FALSE);
4797 }
4798}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00004799
4800/*
4801 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
4802 * spelled word, if there is one.
4803 */
4804 static void
4805spell_back_to_badword()
4806{
4807 pos_T tpos = curwin->w_cursor;
4808
4809 spell_move_to(BACKWARD, TRUE, TRUE);
4810 if (curwin->w_cursor.col != tpos.col)
4811 start_arrow(&tpos);
4812}
Bram Moolenaar217ad922005-03-20 22:37:15 +00004813#endif
4814
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815/*
4816 * stop_arrow() is called before a change is made in insert mode.
4817 * If an arrow key has been used, start a new insertion.
4818 * Returns FAIL if undo is impossible, shouldn't insert then.
4819 */
4820 int
4821stop_arrow()
4822{
4823 if (arrow_used)
4824 {
4825 if (u_save_cursor() == OK)
4826 {
4827 arrow_used = FALSE;
4828 ins_need_undo = FALSE;
4829 }
4830 Insstart = curwin->w_cursor; /* new insertion starts here */
4831 Insstart_textlen = linetabsize(ml_get_curline());
4832 ai_col = 0;
4833#ifdef FEAT_VREPLACE
4834 if (State & VREPLACE_FLAG)
4835 {
4836 orig_line_count = curbuf->b_ml.ml_line_count;
4837 vr_lines_changed = 1;
4838 }
4839#endif
4840 ResetRedobuff();
4841 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
4842 }
4843 else if (ins_need_undo)
4844 {
4845 if (u_save_cursor() == OK)
4846 ins_need_undo = FALSE;
4847 }
4848
4849#ifdef FEAT_FOLDING
4850 /* Always open fold at the cursor line when inserting something. */
4851 foldOpenCursor();
4852#endif
4853
4854 return (arrow_used || ins_need_undo ? FAIL : OK);
4855}
4856
4857/*
4858 * do a few things to stop inserting
4859 */
4860 static void
4861stop_insert(end_insert_pos, esc)
4862 pos_T *end_insert_pos; /* where insert ended */
4863 int esc; /* called by ins_esc() */
4864{
4865 int cc;
4866
4867 stop_redo_ins();
4868 replace_flush(); /* abandon replace stack */
4869
4870 /*
4871 * save the inserted text for later redo with ^@
4872 */
4873 vim_free(last_insert);
4874 last_insert = get_inserted();
4875 last_insert_skip = new_insert_skip;
4876
4877 if (!arrow_used)
4878 {
4879 /* Auto-format now. It may seem strange to do this when stopping an
4880 * insertion (or moving the cursor), but it's required when appending
4881 * a line and having it end in a space. But only do it when something
4882 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004883 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004885 pos_T tpos = curwin->w_cursor;
4886
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887 /* When the cursor is at the end of the line after a space the
4888 * formatting will move it to the following word. Avoid that by
4889 * moving the cursor onto the space. */
4890 cc = 'x';
4891 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
4892 {
4893 dec_cursor();
4894 cc = gchar_cursor();
4895 if (!vim_iswhite(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004896 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 }
4898
4899 auto_format(TRUE, FALSE);
4900
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004901 if (vim_iswhite(cc))
4902 {
4903 if (gchar_cursor() != NUL)
4904 inc_cursor();
4905#ifdef FEAT_VIRTUALEDIT
4906 /* If the cursor is still at the same character, also keep
4907 * the "coladd". */
4908 if (gchar_cursor() == NUL
4909 && curwin->w_cursor.lnum == tpos.lnum
4910 && curwin->w_cursor.col == tpos.col)
4911 curwin->w_cursor.coladd = tpos.coladd;
4912#endif
4913 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004914 }
4915
4916 /* If a space was inserted for auto-formatting, remove it now. */
4917 check_auto_format(TRUE);
4918
4919 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004920 * of the line, and put the cursor back.
4921 * Do this when ESC was used or moving the cursor up/down. */
4922 if (did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
4923 && curwin->w_cursor.lnum != end_insert_pos->lnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004924 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004925 pos_T tpos = curwin->w_cursor;
4926
4927 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
4929 --curwin->w_cursor.col;
4930 while (cc = gchar_cursor(), vim_iswhite(cc))
4931 (void)del_char(TRUE);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004932 if (curwin->w_cursor.lnum != tpos.lnum)
4933 curwin->w_cursor = tpos;
4934 else if (cc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004935 ++curwin->w_cursor.col; /* put cursor back on the NUL */
4936
4937#ifdef FEAT_VISUAL
4938 /* <C-S-Right> may have started Visual mode, adjust the position for
4939 * deleted characters. */
4940 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
4941 {
4942 cc = STRLEN(ml_get_curline());
4943 if (VIsual.col > (colnr_T)cc)
4944 {
4945 VIsual.col = cc;
4946# ifdef FEAT_VIRTUALEDIT
4947 VIsual.coladd = 0;
4948# endif
4949 }
4950 }
4951#endif
4952 }
4953 }
4954 did_ai = FALSE;
4955#ifdef FEAT_SMARTINDENT
4956 did_si = FALSE;
4957 can_si = FALSE;
4958 can_si_back = FALSE;
4959#endif
4960
4961 /* set '[ and '] to the inserted text */
4962 curbuf->b_op_start = Insstart;
4963 curbuf->b_op_end = *end_insert_pos;
4964}
4965
4966/*
4967 * Set the last inserted text to a single character.
4968 * Used for the replace command.
4969 */
4970 void
4971set_last_insert(c)
4972 int c;
4973{
4974 char_u *s;
4975
4976 vim_free(last_insert);
4977#ifdef FEAT_MBYTE
4978 last_insert = alloc(MB_MAXBYTES * 3 + 5);
4979#else
4980 last_insert = alloc(6);
4981#endif
4982 if (last_insert != NULL)
4983 {
4984 s = last_insert;
4985 /* Use the CTRL-V only when entering a special char */
4986 if (c < ' ' || c == DEL)
4987 *s++ = Ctrl_V;
4988 s = add_char2buf(c, s);
4989 *s++ = ESC;
4990 *s++ = NUL;
4991 last_insert_skip = 0;
4992 }
4993}
4994
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00004995#if defined(EXITFREE) || defined(PROTO)
4996 void
4997free_last_insert()
4998{
4999 vim_free(last_insert);
5000 last_insert = NULL;
5001}
5002#endif
5003
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004/*
5005 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
5006 * and CSI. Handle multi-byte characters.
5007 * Returns a pointer to after the added bytes.
5008 */
5009 char_u *
5010add_char2buf(c, s)
5011 int c;
5012 char_u *s;
5013{
5014#ifdef FEAT_MBYTE
5015 char_u temp[MB_MAXBYTES];
5016 int i;
5017 int len;
5018
5019 len = (*mb_char2bytes)(c, temp);
5020 for (i = 0; i < len; ++i)
5021 {
5022 c = temp[i];
5023#endif
5024 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
5025 if (c == K_SPECIAL)
5026 {
5027 *s++ = K_SPECIAL;
5028 *s++ = KS_SPECIAL;
5029 *s++ = KE_FILLER;
5030 }
5031#ifdef FEAT_GUI
5032 else if (c == CSI)
5033 {
5034 *s++ = CSI;
5035 *s++ = KS_EXTRA;
5036 *s++ = (int)KE_CSI;
5037 }
5038#endif
5039 else
5040 *s++ = c;
5041#ifdef FEAT_MBYTE
5042 }
5043#endif
5044 return s;
5045}
5046
5047/*
5048 * move cursor to start of line
5049 * if flags & BL_WHITE move to first non-white
5050 * if flags & BL_SOL move to first non-white if startofline is set,
5051 * otherwise keep "curswant" column
5052 * if flags & BL_FIX don't leave the cursor on a NUL.
5053 */
5054 void
5055beginline(flags)
5056 int flags;
5057{
5058 if ((flags & BL_SOL) && !p_sol)
5059 coladvance(curwin->w_curswant);
5060 else
5061 {
5062 curwin->w_cursor.col = 0;
5063#ifdef FEAT_VIRTUALEDIT
5064 curwin->w_cursor.coladd = 0;
5065#endif
5066
5067 if (flags & (BL_WHITE | BL_SOL))
5068 {
5069 char_u *ptr;
5070
5071 for (ptr = ml_get_curline(); vim_iswhite(*ptr)
5072 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
5073 ++curwin->w_cursor.col;
5074 }
5075 curwin->w_set_curswant = TRUE;
5076 }
5077}
5078
5079/*
5080 * oneright oneleft cursor_down cursor_up
5081 *
5082 * Move one char {right,left,down,up}.
5083 * Doesn't move onto the NUL past the end of the line.
5084 * Return OK when successful, FAIL when we hit a line of file boundary.
5085 */
5086
5087 int
5088oneright()
5089{
5090 char_u *ptr;
5091#ifdef FEAT_MBYTE
5092 int l;
5093#endif
5094
5095#ifdef FEAT_VIRTUALEDIT
5096 if (virtual_active())
5097 {
5098 pos_T prevpos = curwin->w_cursor;
5099
5100 /* Adjust for multi-wide char (excluding TAB) */
5101 ptr = ml_get_cursor();
5102 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(
5103#ifdef FEAT_MBYTE
5104 (*mb_ptr2char)(ptr)
5105#else
5106 *ptr
5107#endif
5108 ))
5109 ? ptr2cells(ptr) : 1));
5110 curwin->w_set_curswant = TRUE;
5111 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
5112 return (prevpos.col != curwin->w_cursor.col
5113 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
5114 }
5115#endif
5116
5117 ptr = ml_get_cursor();
5118#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005119 if (has_mbyte && (l = (*mb_ptr2len)(ptr)) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120 {
5121 /* The character under the cursor is a multi-byte character, move
5122 * several bytes right, but don't end up on the NUL. */
5123 if (ptr[l] == NUL)
5124 return FAIL;
5125 curwin->w_cursor.col += l;
5126 }
5127 else
5128#endif
5129 {
5130 if (*ptr++ == NUL || *ptr == NUL)
5131 return FAIL;
5132 ++curwin->w_cursor.col;
5133 }
5134
5135 curwin->w_set_curswant = TRUE;
5136 return OK;
5137}
5138
5139 int
5140oneleft()
5141{
5142#ifdef FEAT_VIRTUALEDIT
5143 if (virtual_active())
5144 {
5145 int width;
5146 int v = getviscol();
5147
5148 if (v == 0)
5149 return FAIL;
5150
5151# ifdef FEAT_LINEBREAK
5152 /* We might get stuck on 'showbreak', skip over it. */
5153 width = 1;
5154 for (;;)
5155 {
5156 coladvance(v - width);
5157 /* getviscol() is slow, skip it when 'showbreak' is empty and
5158 * there are no multi-byte characters */
5159 if ((*p_sbr == NUL
5160# ifdef FEAT_MBYTE
5161 && !has_mbyte
5162# endif
5163 ) || getviscol() < v)
5164 break;
5165 ++width;
5166 }
5167# else
5168 coladvance(v - 1);
5169# endif
5170
5171 if (curwin->w_cursor.coladd == 1)
5172 {
5173 char_u *ptr;
5174
5175 /* Adjust for multi-wide char (not a TAB) */
5176 ptr = ml_get_cursor();
5177 if (*ptr != TAB && vim_isprintc(
5178# ifdef FEAT_MBYTE
5179 (*mb_ptr2char)(ptr)
5180# else
5181 *ptr
5182# endif
5183 ) && ptr2cells(ptr) > 1)
5184 curwin->w_cursor.coladd = 0;
5185 }
5186
5187 curwin->w_set_curswant = TRUE;
5188 return OK;
5189 }
5190#endif
5191
5192 if (curwin->w_cursor.col == 0)
5193 return FAIL;
5194
5195 curwin->w_set_curswant = TRUE;
5196 --curwin->w_cursor.col;
5197
5198#ifdef FEAT_MBYTE
5199 /* if the character on the left of the current cursor is a multi-byte
5200 * character, move to its first byte */
5201 if (has_mbyte)
5202 mb_adjust_cursor();
5203#endif
5204 return OK;
5205}
5206
5207 int
5208cursor_up(n, upd_topline)
5209 long n;
5210 int upd_topline; /* When TRUE: update topline */
5211{
5212 linenr_T lnum;
5213
5214 if (n > 0)
5215 {
5216 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00005217 /* This fails if the cursor is already in the first line or the count
5218 * is larger than the line number and '-' is in 'cpoptions' */
5219 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220 return FAIL;
5221 if (n >= lnum)
5222 lnum = 1;
5223 else
5224#ifdef FEAT_FOLDING
5225 if (hasAnyFolding(curwin))
5226 {
5227 /*
5228 * Count each sequence of folded lines as one logical line.
5229 */
5230 /* go to the the start of the current fold */
5231 (void)hasFolding(lnum, &lnum, NULL);
5232
5233 while (n--)
5234 {
5235 /* move up one line */
5236 --lnum;
5237 if (lnum <= 1)
5238 break;
5239 /* If we entered a fold, move to the beginning, unless in
5240 * Insert mode or when 'foldopen' contains "all": it will open
5241 * in a moment. */
5242 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
5243 (void)hasFolding(lnum, &lnum, NULL);
5244 }
5245 if (lnum < 1)
5246 lnum = 1;
5247 }
5248 else
5249#endif
5250 lnum -= n;
5251 curwin->w_cursor.lnum = lnum;
5252 }
5253
5254 /* try to advance to the column we want to be at */
5255 coladvance(curwin->w_curswant);
5256
5257 if (upd_topline)
5258 update_topline(); /* make sure curwin->w_topline is valid */
5259
5260 return OK;
5261}
5262
5263/*
5264 * Cursor down a number of logical lines.
5265 */
5266 int
5267cursor_down(n, upd_topline)
5268 long n;
5269 int upd_topline; /* When TRUE: update topline */
5270{
5271 linenr_T lnum;
5272
5273 if (n > 0)
5274 {
5275 lnum = curwin->w_cursor.lnum;
5276#ifdef FEAT_FOLDING
5277 /* Move to last line of fold, will fail if it's the end-of-file. */
5278 (void)hasFolding(lnum, NULL, &lnum);
5279#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00005280 /* This fails if the cursor is already in the last line or would move
5281 * beyound the last line and '-' is in 'cpoptions' */
5282 if (lnum >= curbuf->b_ml.ml_line_count
5283 || (lnum + n > curbuf->b_ml.ml_line_count
5284 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285 return FAIL;
5286 if (lnum + n >= curbuf->b_ml.ml_line_count)
5287 lnum = curbuf->b_ml.ml_line_count;
5288 else
5289#ifdef FEAT_FOLDING
5290 if (hasAnyFolding(curwin))
5291 {
5292 linenr_T last;
5293
5294 /* count each sequence of folded lines as one logical line */
5295 while (n--)
5296 {
5297 if (hasFolding(lnum, NULL, &last))
5298 lnum = last + 1;
5299 else
5300 ++lnum;
5301 if (lnum >= curbuf->b_ml.ml_line_count)
5302 break;
5303 }
5304 if (lnum > curbuf->b_ml.ml_line_count)
5305 lnum = curbuf->b_ml.ml_line_count;
5306 }
5307 else
5308#endif
5309 lnum += n;
5310 curwin->w_cursor.lnum = lnum;
5311 }
5312
5313 /* try to advance to the column we want to be at */
5314 coladvance(curwin->w_curswant);
5315
5316 if (upd_topline)
5317 update_topline(); /* make sure curwin->w_topline is valid */
5318
5319 return OK;
5320}
5321
5322/*
5323 * Stuff the last inserted text in the read buffer.
5324 * Last_insert actually is a copy of the redo buffer, so we
5325 * first have to remove the command.
5326 */
5327 int
5328stuff_inserted(c, count, no_esc)
5329 int c; /* Command character to be inserted */
5330 long count; /* Repeat this many times */
5331 int no_esc; /* Don't add an ESC at the end */
5332{
5333 char_u *esc_ptr;
5334 char_u *ptr;
5335 char_u *last_ptr;
5336 char_u last = NUL;
5337
5338 ptr = get_last_insert();
5339 if (ptr == NULL)
5340 {
5341 EMSG(_(e_noinstext));
5342 return FAIL;
5343 }
5344
5345 /* may want to stuff the command character, to start Insert mode */
5346 if (c != NUL)
5347 stuffcharReadbuff(c);
5348 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
5349 *esc_ptr = NUL; /* remove the ESC */
5350
5351 /* when the last char is either "0" or "^" it will be quoted if no ESC
5352 * comes after it OR if it will inserted more than once and "ptr"
5353 * starts with ^D. -- Acevedo
5354 */
5355 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
5356 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
5357 && (no_esc || (*ptr == Ctrl_D && count > 1)))
5358 {
5359 last = *last_ptr;
5360 *last_ptr = NUL;
5361 }
5362
5363 do
5364 {
5365 stuffReadbuff(ptr);
5366 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
5367 if (last)
5368 stuffReadbuff((char_u *)(last == '0'
5369 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
5370 : IF_EB("\026^", CTRL_V_STR "^")));
5371 }
5372 while (--count > 0);
5373
5374 if (last)
5375 *last_ptr = last;
5376
5377 if (esc_ptr != NULL)
5378 *esc_ptr = ESC; /* put the ESC back */
5379
5380 /* may want to stuff a trailing ESC, to get out of Insert mode */
5381 if (!no_esc)
5382 stuffcharReadbuff(ESC);
5383
5384 return OK;
5385}
5386
5387 char_u *
5388get_last_insert()
5389{
5390 if (last_insert == NULL)
5391 return NULL;
5392 return last_insert + last_insert_skip;
5393}
5394
5395/*
5396 * Get last inserted string, and remove trailing <Esc>.
5397 * Returns pointer to allocated memory (must be freed) or NULL.
5398 */
5399 char_u *
5400get_last_insert_save()
5401{
5402 char_u *s;
5403 int len;
5404
5405 if (last_insert == NULL)
5406 return NULL;
5407 s = vim_strsave(last_insert + last_insert_skip);
5408 if (s != NULL)
5409 {
5410 len = (int)STRLEN(s);
5411 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
5412 s[len - 1] = NUL;
5413 }
5414 return s;
5415}
5416
5417/*
5418 * Check the word in front of the cursor for an abbreviation.
5419 * Called when the non-id character "c" has been entered.
5420 * When an abbreviation is recognized it is removed from the text and
5421 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
5422 */
5423 static int
5424echeck_abbr(c)
5425 int c;
5426{
5427 /* Don't check for abbreviation in paste mode, when disabled and just
5428 * after moving around with cursor keys. */
5429 if (p_paste || no_abbr || arrow_used)
5430 return FALSE;
5431
5432 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
5433 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
5434}
5435
5436/*
5437 * replace-stack functions
5438 *
5439 * When replacing characters, the replaced characters are remembered for each
5440 * new character. This is used to re-insert the old text when backspacing.
5441 *
5442 * There is a NUL headed list of characters for each character that is
5443 * currently in the file after the insertion point. When BS is used, one NUL
5444 * headed list is put back for the deleted character.
5445 *
5446 * For a newline, there are two NUL headed lists. One contains the characters
5447 * that the NL replaced. The extra one stores the characters after the cursor
5448 * that were deleted (always white space).
5449 *
5450 * Replace_offset is normally 0, in which case replace_push will add a new
5451 * character at the end of the stack. If replace_offset is not 0, that many
5452 * characters will be left on the stack above the newly inserted character.
5453 */
5454
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00005455static char_u *replace_stack = NULL;
5456static long replace_stack_nr = 0; /* next entry in replace stack */
5457static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005458
5459 void
5460replace_push(c)
5461 int c; /* character that is replaced (NUL is none) */
5462{
5463 char_u *p;
5464
5465 if (replace_stack_nr < replace_offset) /* nothing to do */
5466 return;
5467 if (replace_stack_len <= replace_stack_nr)
5468 {
5469 replace_stack_len += 50;
5470 p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
5471 if (p == NULL) /* out of memory */
5472 {
5473 replace_stack_len -= 50;
5474 return;
5475 }
5476 if (replace_stack != NULL)
5477 {
5478 mch_memmove(p, replace_stack,
5479 (size_t)(replace_stack_nr * sizeof(char_u)));
5480 vim_free(replace_stack);
5481 }
5482 replace_stack = p;
5483 }
5484 p = replace_stack + replace_stack_nr - replace_offset;
5485 if (replace_offset)
5486 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
5487 *p = c;
5488 ++replace_stack_nr;
5489}
5490
5491/*
5492 * call replace_push(c) with replace_offset set to the first NUL.
5493 */
5494 static void
5495replace_push_off(c)
5496 int c;
5497{
5498 char_u *p;
5499
5500 p = replace_stack + replace_stack_nr;
5501 for (replace_offset = 1; replace_offset < replace_stack_nr;
5502 ++replace_offset)
5503 if (*--p == NUL)
5504 break;
5505 replace_push(c);
5506 replace_offset = 0;
5507}
5508
5509/*
5510 * Pop one item from the replace stack.
5511 * return -1 if stack empty
5512 * return replaced character or NUL otherwise
5513 */
5514 static int
5515replace_pop()
5516{
5517 if (replace_stack_nr == 0)
5518 return -1;
5519 return (int)replace_stack[--replace_stack_nr];
5520}
5521
5522/*
5523 * Join the top two items on the replace stack. This removes to "off"'th NUL
5524 * encountered.
5525 */
5526 static void
5527replace_join(off)
5528 int off; /* offset for which NUL to remove */
5529{
5530 int i;
5531
5532 for (i = replace_stack_nr; --i >= 0; )
5533 if (replace_stack[i] == NUL && off-- <= 0)
5534 {
5535 --replace_stack_nr;
5536 mch_memmove(replace_stack + i, replace_stack + i + 1,
5537 (size_t)(replace_stack_nr - i));
5538 return;
5539 }
5540}
5541
5542/*
5543 * Pop bytes from the replace stack until a NUL is found, and insert them
5544 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
5545 */
5546 static void
5547replace_pop_ins()
5548{
5549 int cc;
5550 int oldState = State;
5551
5552 State = NORMAL; /* don't want REPLACE here */
5553 while ((cc = replace_pop()) > 0)
5554 {
5555#ifdef FEAT_MBYTE
5556 mb_replace_pop_ins(cc);
5557#else
5558 ins_char(cc);
5559#endif
5560 dec_cursor();
5561 }
5562 State = oldState;
5563}
5564
5565#ifdef FEAT_MBYTE
5566/*
5567 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
5568 * indicates a multi-byte char, pop the other bytes too.
5569 */
5570 static void
5571mb_replace_pop_ins(cc)
5572 int cc;
5573{
5574 int n;
5575 char_u buf[MB_MAXBYTES];
5576 int i;
5577 int c;
5578
5579 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
5580 {
5581 buf[0] = cc;
5582 for (i = 1; i < n; ++i)
5583 buf[i] = replace_pop();
5584 ins_bytes_len(buf, n);
5585 }
5586 else
5587 ins_char(cc);
5588
5589 if (enc_utf8)
5590 /* Handle composing chars. */
5591 for (;;)
5592 {
5593 c = replace_pop();
5594 if (c == -1) /* stack empty */
5595 break;
5596 if ((n = MB_BYTE2LEN(c)) == 1)
5597 {
5598 /* Not a multi-byte char, put it back. */
5599 replace_push(c);
5600 break;
5601 }
5602 else
5603 {
5604 buf[0] = c;
5605 for (i = 1; i < n; ++i)
5606 buf[i] = replace_pop();
5607 if (utf_iscomposing(utf_ptr2char(buf)))
5608 ins_bytes_len(buf, n);
5609 else
5610 {
5611 /* Not a composing char, put it back. */
5612 for (i = n - 1; i >= 0; --i)
5613 replace_push(buf[i]);
5614 break;
5615 }
5616 }
5617 }
5618}
5619#endif
5620
5621/*
5622 * make the replace stack empty
5623 * (called when exiting replace mode)
5624 */
5625 static void
5626replace_flush()
5627{
5628 vim_free(replace_stack);
5629 replace_stack = NULL;
5630 replace_stack_len = 0;
5631 replace_stack_nr = 0;
5632}
5633
5634/*
5635 * Handle doing a BS for one character.
5636 * cc < 0: replace stack empty, just move cursor
5637 * cc == 0: character was inserted, delete it
5638 * cc > 0: character was replaced, put cc (first byte of original char) back
5639 * and check for more characters to be put back
5640 */
5641 static void
5642replace_do_bs()
5643{
5644 int cc;
5645#ifdef FEAT_VREPLACE
5646 int orig_len = 0;
5647 int ins_len;
5648 int orig_vcols = 0;
5649 colnr_T start_vcol;
5650 char_u *p;
5651 int i;
5652 int vcol;
5653#endif
5654
5655 cc = replace_pop();
5656 if (cc > 0)
5657 {
5658#ifdef FEAT_VREPLACE
5659 if (State & VREPLACE_FLAG)
5660 {
5661 /* Get the number of screen cells used by the character we are
5662 * going to delete. */
5663 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
5664 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
5665 }
5666#endif
5667#ifdef FEAT_MBYTE
5668 if (has_mbyte)
5669 {
5670 del_char(FALSE);
5671# ifdef FEAT_VREPLACE
5672 if (State & VREPLACE_FLAG)
5673 orig_len = STRLEN(ml_get_cursor());
5674# endif
5675 replace_push(cc);
5676 }
5677 else
5678#endif
5679 {
5680 pchar_cursor(cc);
5681#ifdef FEAT_VREPLACE
5682 if (State & VREPLACE_FLAG)
5683 orig_len = STRLEN(ml_get_cursor()) - 1;
5684#endif
5685 }
5686 replace_pop_ins();
5687
5688#ifdef FEAT_VREPLACE
5689 if (State & VREPLACE_FLAG)
5690 {
5691 /* Get the number of screen cells used by the inserted characters */
5692 p = ml_get_cursor();
5693 ins_len = STRLEN(p) - orig_len;
5694 vcol = start_vcol;
5695 for (i = 0; i < ins_len; ++i)
5696 {
5697 vcol += chartabsize(p + i, vcol);
5698#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005699 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700#endif
5701 }
5702 vcol -= start_vcol;
5703
5704 /* Delete spaces that were inserted after the cursor to keep the
5705 * text aligned. */
5706 curwin->w_cursor.col += ins_len;
5707 while (vcol > orig_vcols && gchar_cursor() == ' ')
5708 {
5709 del_char(FALSE);
5710 ++orig_vcols;
5711 }
5712 curwin->w_cursor.col -= ins_len;
5713 }
5714#endif
5715
5716 /* mark the buffer as changed and prepare for displaying */
5717 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
5718 }
5719 else if (cc == 0)
5720 (void)del_char(FALSE);
5721}
5722
5723#ifdef FEAT_CINDENT
5724/*
5725 * Return TRUE if C-indenting is on.
5726 */
5727 static int
5728cindent_on()
5729{
5730 return (!p_paste && (curbuf->b_p_cin
5731# ifdef FEAT_EVAL
5732 || *curbuf->b_p_inde != NUL
5733# endif
5734 ));
5735}
5736#endif
5737
5738#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
5739/*
5740 * Re-indent the current line, based on the current contents of it and the
5741 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
5742 * confused what all the part that handles Control-T is doing that I'm not.
5743 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
5744 */
5745
5746 void
5747fixthisline(get_the_indent)
5748 int (*get_the_indent) __ARGS((void));
5749{
5750 change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
5751 if (linewhite(curwin->w_cursor.lnum))
5752 did_ai = TRUE; /* delete the indent if the line stays empty */
5753}
5754
5755 void
5756fix_indent()
5757{
5758 if (p_paste)
5759 return;
5760# ifdef FEAT_LISP
5761 if (curbuf->b_p_lisp && curbuf->b_p_ai)
5762 fixthisline(get_lisp_indent);
5763# endif
5764# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
5765 else
5766# endif
5767# ifdef FEAT_CINDENT
5768 if (cindent_on())
5769 do_c_expr_indent();
5770# endif
5771}
5772
5773#endif
5774
5775#ifdef FEAT_CINDENT
5776/*
5777 * return TRUE if 'cinkeys' contains the key "keytyped",
5778 * when == '*': Only if key is preceded with '*' (indent before insert)
5779 * when == '!': Only if key is prededed with '!' (don't insert)
5780 * when == ' ': Only if key is not preceded with '*'(indent afterwards)
5781 *
5782 * "keytyped" can have a few special values:
5783 * KEY_OPEN_FORW
5784 * KEY_OPEN_BACK
5785 * KEY_COMPLETE just finished completion.
5786 *
5787 * If line_is_empty is TRUE accept keys with '0' before them.
5788 */
5789 int
5790in_cinkeys(keytyped, when, line_is_empty)
5791 int keytyped;
5792 int when;
5793 int line_is_empty;
5794{
5795 char_u *look;
5796 int try_match;
5797 int try_match_word;
5798 char_u *p;
5799 char_u *line;
5800 int icase;
5801 int i;
5802
5803#ifdef FEAT_EVAL
5804 if (*curbuf->b_p_inde != NUL)
5805 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
5806 else
5807#endif
5808 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
5809 while (*look)
5810 {
5811 /*
5812 * Find out if we want to try a match with this key, depending on
5813 * 'when' and a '*' or '!' before the key.
5814 */
5815 switch (when)
5816 {
5817 case '*': try_match = (*look == '*'); break;
5818 case '!': try_match = (*look == '!'); break;
5819 default: try_match = (*look != '*'); break;
5820 }
5821 if (*look == '*' || *look == '!')
5822 ++look;
5823
5824 /*
5825 * If there is a '0', only accept a match if the line is empty.
5826 * But may still match when typing last char of a word.
5827 */
5828 if (*look == '0')
5829 {
5830 try_match_word = try_match;
5831 if (!line_is_empty)
5832 try_match = FALSE;
5833 ++look;
5834 }
5835 else
5836 try_match_word = FALSE;
5837
5838 /*
5839 * does it look like a control character?
5840 */
5841 if (*look == '^'
5842#ifdef EBCDIC
5843 && (Ctrl_chr(look[1]) != 0)
5844#else
5845 && look[1] >= '?' && look[1] <= '_'
5846#endif
5847 )
5848 {
5849 if (try_match && keytyped == Ctrl_chr(look[1]))
5850 return TRUE;
5851 look += 2;
5852 }
5853 /*
5854 * 'o' means "o" command, open forward.
5855 * 'O' means "O" command, open backward.
5856 */
5857 else if (*look == 'o')
5858 {
5859 if (try_match && keytyped == KEY_OPEN_FORW)
5860 return TRUE;
5861 ++look;
5862 }
5863 else if (*look == 'O')
5864 {
5865 if (try_match && keytyped == KEY_OPEN_BACK)
5866 return TRUE;
5867 ++look;
5868 }
5869
5870 /*
5871 * 'e' means to check for "else" at start of line and just before the
5872 * cursor.
5873 */
5874 else if (*look == 'e')
5875 {
5876 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
5877 {
5878 p = ml_get_curline();
5879 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
5880 STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
5881 return TRUE;
5882 }
5883 ++look;
5884 }
5885
5886 /*
5887 * ':' only causes an indent if it is at the end of a label or case
5888 * statement, or when it was before typing the ':' (to fix
5889 * class::method for C++).
5890 */
5891 else if (*look == ':')
5892 {
5893 if (try_match && keytyped == ':')
5894 {
5895 p = ml_get_curline();
5896 if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
5897 return TRUE;
5898 if (curwin->w_cursor.col > 2
5899 && p[curwin->w_cursor.col - 1] == ':'
5900 && p[curwin->w_cursor.col - 2] == ':')
5901 {
5902 p[curwin->w_cursor.col - 1] = ' ';
5903 i = (cin_iscase(p) || cin_isscopedecl(p)
5904 || cin_islabel(30));
5905 p = ml_get_curline();
5906 p[curwin->w_cursor.col - 1] = ':';
5907 if (i)
5908 return TRUE;
5909 }
5910 }
5911 ++look;
5912 }
5913
5914
5915 /*
5916 * Is it a key in <>, maybe?
5917 */
5918 else if (*look == '<')
5919 {
5920 if (try_match)
5921 {
5922 /*
5923 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
5924 * <:> and <!> so that people can re-indent on o, O, e, 0, <,
5925 * >, *, : and ! keys if they really really want to.
5926 */
5927 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
5928 && keytyped == look[1])
5929 return TRUE;
5930
5931 if (keytyped == get_special_key_code(look + 1))
5932 return TRUE;
5933 }
5934 while (*look && *look != '>')
5935 look++;
5936 while (*look == '>')
5937 look++;
5938 }
5939
5940 /*
5941 * Is it a word: "=word"?
5942 */
5943 else if (*look == '=' && look[1] != ',' && look[1] != NUL)
5944 {
5945 ++look;
5946 if (*look == '~')
5947 {
5948 icase = TRUE;
5949 ++look;
5950 }
5951 else
5952 icase = FALSE;
5953 p = vim_strchr(look, ',');
5954 if (p == NULL)
5955 p = look + STRLEN(look);
5956 if ((try_match || try_match_word)
5957 && curwin->w_cursor.col >= (colnr_T)(p - look))
5958 {
5959 int match = FALSE;
5960
5961#ifdef FEAT_INS_EXPAND
5962 if (keytyped == KEY_COMPLETE)
5963 {
5964 char_u *s;
5965
5966 /* Just completed a word, check if it starts with "look".
5967 * search back for the start of a word. */
5968 line = ml_get_curline();
5969# ifdef FEAT_MBYTE
5970 if (has_mbyte)
5971 {
5972 char_u *n;
5973
5974 for (s = line + curwin->w_cursor.col; s > line; s = n)
5975 {
5976 n = mb_prevptr(line, s);
5977 if (!vim_iswordp(n))
5978 break;
5979 }
5980 }
5981 else
5982# endif
5983 for (s = line + curwin->w_cursor.col; s > line; --s)
5984 if (!vim_iswordc(s[-1]))
5985 break;
5986 if (s + (p - look) <= line + curwin->w_cursor.col
5987 && (icase
5988 ? MB_STRNICMP(s, look, p - look)
5989 : STRNCMP(s, look, p - look)) == 0)
5990 match = TRUE;
5991 }
5992 else
5993#endif
5994 /* TODO: multi-byte */
5995 if (keytyped == (int)p[-1] || (icase && keytyped < 256
5996 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
5997 {
5998 line = ml_get_cursor();
5999 if ((curwin->w_cursor.col == (colnr_T)(p - look)
6000 || !vim_iswordc(line[-(p - look) - 1]))
6001 && (icase
6002 ? MB_STRNICMP(line - (p - look), look, p - look)
6003 : STRNCMP(line - (p - look), look, p - look))
6004 == 0)
6005 match = TRUE;
6006 }
6007 if (match && try_match_word && !try_match)
6008 {
6009 /* "0=word": Check if there are only blanks before the
6010 * word. */
6011 line = ml_get_curline();
6012 if ((int)(skipwhite(line) - line) !=
6013 (int)(curwin->w_cursor.col - (p - look)))
6014 match = FALSE;
6015 }
6016 if (match)
6017 return TRUE;
6018 }
6019 look = p;
6020 }
6021
6022 /*
6023 * ok, it's a boring generic character.
6024 */
6025 else
6026 {
6027 if (try_match && *look == keytyped)
6028 return TRUE;
6029 ++look;
6030 }
6031
6032 /*
6033 * Skip over ", ".
6034 */
6035 look = skip_to_option_part(look);
6036 }
6037 return FALSE;
6038}
6039#endif /* FEAT_CINDENT */
6040
6041#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
6042/*
6043 * Map Hebrew keyboard when in hkmap mode.
6044 */
6045 int
6046hkmap(c)
6047 int c;
6048{
6049 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
6050 {
6051 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
6052 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
6053 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
6054 static char_u map[26] =
6055 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
6056 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
6057 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
6058 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
6059 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
6060 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
6061 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
6062 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
6063 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
6064
6065 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
6066 return (int)(map[CharOrd(c)] - 1 + p_aleph);
6067 /* '-1'='sofit' */
6068 else if (c == 'x')
6069 return 'X';
6070 else if (c == 'q')
6071 return '\''; /* {geresh}={'} */
6072 else if (c == 246)
6073 return ' '; /* \"o --> ' ' for a german keyboard */
6074 else if (c == 228)
6075 return ' '; /* \"a --> ' ' -- / -- */
6076 else if (c == 252)
6077 return ' '; /* \"u --> ' ' -- / -- */
6078#ifdef EBCDIC
6079 else if (islower(c))
6080#else
6081 /* NOTE: islower() does not do the right thing for us on Linux so we
6082 * do this the same was as 5.7 and previous, so it works correctly on
6083 * all systems. Specifically, the e.g. Delete and Arrow keys are
6084 * munged and won't work if e.g. searching for Hebrew text.
6085 */
6086 else if (c >= 'a' && c <= 'z')
6087#endif
6088 return (int)(map[CharOrdLow(c)] + p_aleph);
6089 else
6090 return c;
6091 }
6092 else
6093 {
6094 switch (c)
6095 {
6096 case '`': return ';';
6097 case '/': return '.';
6098 case '\'': return ',';
6099 case 'q': return '/';
6100 case 'w': return '\'';
6101
6102 /* Hebrew letters - set offset from 'a' */
6103 case ',': c = '{'; break;
6104 case '.': c = 'v'; break;
6105 case ';': c = 't'; break;
6106 default: {
6107 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
6108
6109#ifdef EBCDIC
6110 /* see note about islower() above */
6111 if (!islower(c))
6112#else
6113 if (c < 'a' || c > 'z')
6114#endif
6115 return c;
6116 c = str[CharOrdLow(c)];
6117 break;
6118 }
6119 }
6120
6121 return (int)(CharOrdLow(c) + p_aleph);
6122 }
6123}
6124#endif
6125
6126 static void
6127ins_reg()
6128{
6129 int need_redraw = FALSE;
6130 int regname;
6131 int literally = 0;
6132
6133 /*
6134 * If we are going to wait for a character, show a '"'.
6135 */
6136 pc_status = PC_STATUS_UNSET;
6137 if (redrawing() && !char_avail())
6138 {
6139 /* may need to redraw when no more chars available now */
6140 ins_redraw();
6141
6142 edit_putchar('"', TRUE);
6143#ifdef FEAT_CMDL_INFO
6144 add_to_showcmd_c(Ctrl_R);
6145#endif
6146 }
6147
6148#ifdef USE_ON_FLY_SCROLL
6149 dont_scroll = TRUE; /* disallow scrolling here */
6150#endif
6151
6152 /*
6153 * Don't map the register name. This also prevents the mode message to be
6154 * deleted when ESC is hit.
6155 */
6156 ++no_mapping;
6157 regname = safe_vgetc();
6158#ifdef FEAT_LANGMAP
6159 LANGMAP_ADJUST(regname, TRUE);
6160#endif
6161 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
6162 {
6163 /* Get a third key for literal register insertion */
6164 literally = regname;
6165#ifdef FEAT_CMDL_INFO
6166 add_to_showcmd_c(literally);
6167#endif
6168 regname = safe_vgetc();
6169#ifdef FEAT_LANGMAP
6170 LANGMAP_ADJUST(regname, TRUE);
6171#endif
6172 }
6173 --no_mapping;
6174
6175#ifdef FEAT_EVAL
6176 /*
6177 * Don't call u_sync() while getting the expression,
6178 * evaluating it or giving an error message for it!
6179 */
6180 ++no_u_sync;
6181 if (regname == '=')
6182 {
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006183# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006185# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006186 regname = get_expr_register();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006187# ifdef USE_IM_CONTROL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188 /* Restore the Input Method. */
6189 if (im_on)
6190 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006191# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00006193 if (regname == NUL || !valid_yank_reg(regname, FALSE))
6194 {
6195 vim_beep();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00006197 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198 else
6199 {
6200#endif
6201 if (literally == Ctrl_O || literally == Ctrl_P)
6202 {
6203 /* Append the command to the redo buffer. */
6204 AppendCharToRedobuff(Ctrl_R);
6205 AppendCharToRedobuff(literally);
6206 AppendCharToRedobuff(regname);
6207
6208 do_put(regname, BACKWARD, 1L,
6209 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
6210 }
6211 else if (insert_reg(regname, literally) == FAIL)
6212 {
6213 vim_beep();
6214 need_redraw = TRUE; /* remove the '"' */
6215 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00006216 else if (stop_insert_mode)
6217 /* When the '=' register was used and a function was invoked that
6218 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
6219 * insert anything, need to remove the '"' */
6220 need_redraw = TRUE;
6221
Bram Moolenaar071d4272004-06-13 20:20:40 +00006222#ifdef FEAT_EVAL
6223 }
6224 --no_u_sync;
6225#endif
6226#ifdef FEAT_CMDL_INFO
6227 clear_showcmd();
6228#endif
6229
6230 /* If the inserted register is empty, we need to remove the '"' */
6231 if (need_redraw || stuff_empty())
6232 edit_unputchar();
6233}
6234
6235/*
6236 * CTRL-G commands in Insert mode.
6237 */
6238 static void
6239ins_ctrl_g()
6240{
6241 int c;
6242
6243#ifdef FEAT_INS_EXPAND
6244 /* Right after CTRL-X the cursor will be after the ruler. */
6245 setcursor();
6246#endif
6247
6248 /*
6249 * Don't map the second key. This also prevents the mode message to be
6250 * deleted when ESC is hit.
6251 */
6252 ++no_mapping;
6253 c = safe_vgetc();
6254 --no_mapping;
6255 switch (c)
6256 {
6257 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
6258 case K_UP:
6259 case Ctrl_K:
6260 case 'k': ins_up(TRUE);
6261 break;
6262
6263 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
6264 case K_DOWN:
6265 case Ctrl_J:
6266 case 'j': ins_down(TRUE);
6267 break;
6268
6269 /* CTRL-G u: start new undoable edit */
6270 case 'u': u_sync();
6271 ins_need_undo = TRUE;
6272 break;
6273
6274 /* Unknown CTRL-G command, reserved for future expansion. */
6275 default: vim_beep();
6276 }
6277}
6278
6279/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006280 * CTRL-^ in Insert mode.
6281 */
6282 static void
6283ins_ctrl_hat()
6284{
6285 if (map_to_exists_mode((char_u *)"", LANGMAP))
6286 {
6287 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
6288 if (State & LANGMAP)
6289 {
6290 curbuf->b_p_iminsert = B_IMODE_NONE;
6291 State &= ~LANGMAP;
6292 }
6293 else
6294 {
6295 curbuf->b_p_iminsert = B_IMODE_LMAP;
6296 State |= LANGMAP;
6297#ifdef USE_IM_CONTROL
6298 im_set_active(FALSE);
6299#endif
6300 }
6301 }
6302#ifdef USE_IM_CONTROL
6303 else
6304 {
6305 /* There are no ":lmap" mappings, toggle IM */
6306 if (im_get_status())
6307 {
6308 curbuf->b_p_iminsert = B_IMODE_NONE;
6309 im_set_active(FALSE);
6310 }
6311 else
6312 {
6313 curbuf->b_p_iminsert = B_IMODE_IM;
6314 State &= ~LANGMAP;
6315 im_set_active(TRUE);
6316 }
6317 }
6318#endif
6319 set_iminsert_global();
6320 showmode();
6321#ifdef FEAT_GUI
6322 /* may show different cursor shape or color */
6323 if (gui.in_use)
6324 gui_update_cursor(TRUE, FALSE);
6325#endif
6326#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
6327 /* Show/unshow value of 'keymap' in status lines. */
6328 status_redraw_curbuf();
6329#endif
6330}
6331
6332/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006333 * Handle ESC in insert mode.
6334 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
6335 * insert.
6336 */
6337 static int
Bram Moolenaar488c6512005-08-11 20:09:58 +00006338ins_esc(count, cmdchar, nomove)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006339 long *count;
6340 int cmdchar;
Bram Moolenaar488c6512005-08-11 20:09:58 +00006341 int nomove; /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006342{
6343 int temp;
6344 static int disabled_redraw = FALSE;
6345
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006346#ifdef FEAT_SYN_HL
6347 check_spell_redraw();
6348#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006349#if defined(FEAT_HANGULIN)
6350# if defined(ESC_CHG_TO_ENG_MODE)
6351 hangul_input_state_set(0);
6352# endif
6353 if (composing_hangul)
6354 {
6355 push_raw_key(composing_hangul_buffer, 2);
6356 composing_hangul = 0;
6357 }
6358#endif
6359#if defined(FEAT_MBYTE) && defined(MACOS_CLASSIC)
6360 previous_script = GetScriptManagerVariable(smKeyScript);
6361 KeyScript(smKeyRoman); /* or smKeySysScript */
6362#endif
6363
6364 temp = curwin->w_cursor.col;
6365 if (disabled_redraw)
6366 {
6367 --RedrawingDisabled;
6368 disabled_redraw = FALSE;
6369 }
6370 if (!arrow_used)
6371 {
6372 /*
6373 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00006374 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
6375 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376 */
6377 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00006378 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006379
6380 /*
6381 * Repeating insert may take a long time. Check for
6382 * interrupt now and then.
6383 */
6384 if (*count > 0)
6385 {
6386 line_breakcheck();
6387 if (got_int)
6388 *count = 0;
6389 }
6390
6391 if (--*count > 0) /* repeat what was typed */
6392 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00006393 /* Vi repeats the insert without replacing characters. */
6394 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
6395 State &= ~REPLACE_FLAG;
6396
Bram Moolenaar071d4272004-06-13 20:20:40 +00006397 (void)start_redo_ins();
6398 if (cmdchar == 'r' || cmdchar == 'v')
6399 stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
6400 ++RedrawingDisabled;
6401 disabled_redraw = TRUE;
6402 return FALSE; /* repeat the insert */
6403 }
6404 stop_insert(&curwin->w_cursor, TRUE);
6405 undisplay_dollar();
6406 }
6407
6408 /* When an autoindent was removed, curswant stays after the
6409 * indent */
6410 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
6411 curwin->w_set_curswant = TRUE;
6412
6413 /* Remember the last Insert position in the '^ mark. */
6414 if (!cmdmod.keepjumps)
6415 curbuf->b_last_insert = curwin->w_cursor;
6416
6417 /*
6418 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00006419 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006420 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00006421 if (!nomove
6422 && (curwin->w_cursor.col != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423#ifdef FEAT_VIRTUALEDIT
6424 || curwin->w_cursor.coladd > 0
6425#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00006426 )
6427 && (restart_edit == NUL
6428 || (gchar_cursor() == NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006429#ifdef FEAT_VISUAL
Bram Moolenaar488c6512005-08-11 20:09:58 +00006430 && !VIsual_active
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431#endif
Bram Moolenaar488c6512005-08-11 20:09:58 +00006432 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433#ifdef FEAT_RIGHTLEFT
6434 && !revins_on
6435#endif
6436 )
6437 {
6438#ifdef FEAT_VIRTUALEDIT
6439 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
6440 {
6441 oneleft();
6442 if (restart_edit != NUL)
6443 ++curwin->w_cursor.coladd;
6444 }
6445 else
6446#endif
6447 {
6448 --curwin->w_cursor.col;
6449#ifdef FEAT_MBYTE
6450 /* Correct cursor for multi-byte character. */
6451 if (has_mbyte)
6452 mb_adjust_cursor();
6453#endif
6454 }
6455 }
6456
6457#ifdef USE_IM_CONTROL
6458 /* Disable IM to allow typing English directly for Normal mode commands.
6459 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
6460 * well). */
6461 if (!(State & LANGMAP))
6462 im_save_status(&curbuf->b_p_iminsert);
6463 im_set_active(FALSE);
6464#endif
6465
6466 State = NORMAL;
6467 /* need to position cursor again (e.g. when on a TAB ) */
6468 changed_cline_bef_curs();
6469
6470#ifdef FEAT_MOUSE
6471 setmouse();
6472#endif
6473#ifdef CURSOR_SHAPE
6474 ui_cursor_shape(); /* may show different cursor shape */
6475#endif
6476
6477 /*
6478 * When recording or for CTRL-O, need to display the new mode.
6479 * Otherwise remove the mode message.
6480 */
6481 if (Recording || restart_edit != NUL)
6482 showmode();
6483 else if (p_smd)
6484 MSG("");
6485
6486 return TRUE; /* exit Insert mode */
6487}
6488
6489#ifdef FEAT_RIGHTLEFT
6490/*
6491 * Toggle language: hkmap and revins_on.
6492 * Move to end of reverse inserted text.
6493 */
6494 static void
6495ins_ctrl_()
6496{
6497 if (revins_on && revins_chars && revins_scol >= 0)
6498 {
6499 while (gchar_cursor() != NUL && revins_chars--)
6500 ++curwin->w_cursor.col;
6501 }
6502 p_ri = !p_ri;
6503 revins_on = (State == INSERT && p_ri);
6504 if (revins_on)
6505 {
6506 revins_scol = curwin->w_cursor.col;
6507 revins_legal++;
6508 revins_chars = 0;
6509 undisplay_dollar();
6510 }
6511 else
6512 revins_scol = -1;
6513#ifdef FEAT_FKMAP
6514 if (p_altkeymap)
6515 {
6516 /*
6517 * to be consistent also for redo command, using '.'
6518 * set arrow_used to true and stop it - causing to redo
6519 * characters entered in one mode (normal/reverse insert).
6520 */
6521 arrow_used = TRUE;
6522 (void)stop_arrow();
6523 p_fkmap = curwin->w_p_rl ^ p_ri;
6524 if (p_fkmap && p_ri)
6525 State = INSERT;
6526 }
6527 else
6528#endif
6529 p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
6530 showmode();
6531}
6532#endif
6533
6534#ifdef FEAT_VISUAL
6535/*
6536 * If 'keymodel' contains "startsel", may start selection.
6537 * Returns TRUE when a CTRL-O and other keys stuffed.
6538 */
6539 static int
6540ins_start_select(c)
6541 int c;
6542{
6543 if (km_startsel)
6544 switch (c)
6545 {
6546 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006547 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006548 case K_PAGEUP:
6549 case K_KPAGEUP:
6550 case K_PAGEDOWN:
6551 case K_KPAGEDOWN:
6552# ifdef MACOS
6553 case K_LEFT:
6554 case K_RIGHT:
6555 case K_UP:
6556 case K_DOWN:
6557 case K_END:
6558 case K_HOME:
6559# endif
6560 if (!(mod_mask & MOD_MASK_SHIFT))
6561 break;
6562 /* FALLTHROUGH */
6563 case K_S_LEFT:
6564 case K_S_RIGHT:
6565 case K_S_UP:
6566 case K_S_DOWN:
6567 case K_S_END:
6568 case K_S_HOME:
6569 /* Start selection right away, the cursor can move with
6570 * CTRL-O when beyond the end of the line. */
6571 start_selection();
6572
6573 /* Execute the key in (insert) Select mode. */
6574 stuffcharReadbuff(Ctrl_O);
6575 if (mod_mask)
6576 {
6577 char_u buf[4];
6578
6579 buf[0] = K_SPECIAL;
6580 buf[1] = KS_MODIFIER;
6581 buf[2] = mod_mask;
6582 buf[3] = NUL;
6583 stuffReadbuff(buf);
6584 }
6585 stuffcharReadbuff(c);
6586 return TRUE;
6587 }
6588 return FALSE;
6589}
6590#endif
6591
6592/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006593 * <Insert> key in Insert mode: toggle insert/remplace mode.
6594 */
6595 static void
6596ins_insert(replaceState)
6597 int replaceState;
6598{
6599#ifdef FEAT_FKMAP
6600 if (p_fkmap && p_ri)
6601 {
6602 beep_flush();
6603 EMSG(farsi_text_3); /* encoded in Farsi */
6604 return;
6605 }
6606#endif
6607
6608#ifdef FEAT_AUTOCMD
6609 set_vim_var_string(VV_INSERTMODE,
6610 (char_u *)((State & REPLACE_FLAG) ? "i" :
6611 replaceState == VREPLACE ? "v" : "r"), 1);
6612 apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
6613#endif
6614 if (State & REPLACE_FLAG)
6615 State = INSERT | (State & LANGMAP);
6616 else
6617 State = replaceState | (State & LANGMAP);
6618 AppendCharToRedobuff(K_INS);
6619 showmode();
6620#ifdef CURSOR_SHAPE
6621 ui_cursor_shape(); /* may show different cursor shape */
6622#endif
6623}
6624
6625/*
6626 * Pressed CTRL-O in Insert mode.
6627 */
6628 static void
6629ins_ctrl_o()
6630{
6631#ifdef FEAT_VREPLACE
6632 if (State & VREPLACE_FLAG)
6633 restart_edit = 'V';
6634 else
6635#endif
6636 if (State & REPLACE_FLAG)
6637 restart_edit = 'R';
6638 else
6639 restart_edit = 'I';
6640#ifdef FEAT_VIRTUALEDIT
6641 if (virtual_active())
6642 ins_at_eol = FALSE; /* cursor always keeps its column */
6643 else
6644#endif
6645 ins_at_eol = (gchar_cursor() == NUL);
6646}
6647
6648/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649 * If the cursor is on an indent, ^T/^D insert/delete one
6650 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
6651 * Always round the indent to 'shiftwith', this is compatible
6652 * with vi. But vi only supports ^T and ^D after an
6653 * autoindent, we support it everywhere.
6654 */
6655 static void
6656ins_shift(c, lastc)
6657 int c;
6658 int lastc;
6659{
6660 if (stop_arrow() == FAIL)
6661 return;
6662 AppendCharToRedobuff(c);
6663
6664 /*
6665 * 0^D and ^^D: remove all indent.
6666 */
6667 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
6668 {
6669 --curwin->w_cursor.col;
6670 (void)del_char(FALSE); /* delete the '^' or '0' */
6671 /* In Replace mode, restore the characters that '^' or '0' replaced. */
6672 if (State & REPLACE_FLAG)
6673 replace_pop_ins();
6674 if (lastc == '^')
6675 old_indent = get_indent(); /* remember curr. indent */
6676 change_indent(INDENT_SET, 0, TRUE, 0);
6677 }
6678 else
6679 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
6680
6681 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
6682 did_ai = FALSE;
6683#ifdef FEAT_SMARTINDENT
6684 did_si = FALSE;
6685 can_si = FALSE;
6686 can_si_back = FALSE;
6687#endif
6688#ifdef FEAT_CINDENT
6689 can_cindent = FALSE; /* no cindenting after ^D or ^T */
6690#endif
6691}
6692
6693 static void
6694ins_del()
6695{
6696 int temp;
6697
6698 if (stop_arrow() == FAIL)
6699 return;
6700 if (gchar_cursor() == NUL) /* delete newline */
6701 {
6702 temp = curwin->w_cursor.col;
6703 if (!can_bs(BS_EOL) /* only if "eol" included */
6704 || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
6705 (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
6706 || do_join(FALSE) == FAIL)
6707 vim_beep();
6708 else
6709 curwin->w_cursor.col = temp;
6710 }
6711 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
6712 vim_beep();
6713 did_ai = FALSE;
6714#ifdef FEAT_SMARTINDENT
6715 did_si = FALSE;
6716 can_si = FALSE;
6717 can_si_back = FALSE;
6718#endif
6719 AppendCharToRedobuff(K_DEL);
6720}
6721
6722/*
6723 * Handle Backspace, delete-word and delete-line in Insert mode.
6724 * Return TRUE when backspace was actually used.
6725 */
6726 static int
6727ins_bs(c, mode, inserted_space_p)
6728 int c;
6729 int mode;
6730 int *inserted_space_p;
6731{
6732 linenr_T lnum;
6733 int cc;
6734 int temp = 0; /* init for GCC */
6735 colnr_T mincol;
6736 int did_backspace = FALSE;
6737 int in_indent;
6738 int oldState;
6739#ifdef FEAT_MBYTE
6740 int p1, p2;
6741#endif
6742
6743 /*
6744 * can't delete anything in an empty file
6745 * can't backup past first character in buffer
6746 * can't backup past starting point unless 'backspace' > 1
6747 * can backup to a previous line if 'backspace' == 0
6748 */
6749 if ( bufempty()
6750 || (
6751#ifdef FEAT_RIGHTLEFT
6752 !revins_on &&
6753#endif
6754 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
6755 || (!can_bs(BS_START)
6756 && (arrow_used
6757 || (curwin->w_cursor.lnum == Insstart.lnum
6758 && curwin->w_cursor.col <= Insstart.col)))
6759 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
6760 && curwin->w_cursor.col <= ai_col)
6761 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
6762 {
6763 vim_beep();
6764 return FALSE;
6765 }
6766
6767 if (stop_arrow() == FAIL)
6768 return FALSE;
6769 in_indent = inindent(0);
6770#ifdef FEAT_CINDENT
6771 if (in_indent)
6772 can_cindent = FALSE;
6773#endif
6774#ifdef FEAT_COMMENTS
6775 end_comment_pending = NUL; /* After BS, don't auto-end comment */
6776#endif
6777#ifdef FEAT_RIGHTLEFT
6778 if (revins_on) /* put cursor after last inserted char */
6779 inc_cursor();
6780#endif
6781
6782#ifdef FEAT_VIRTUALEDIT
6783 /* Virtualedit:
6784 * BACKSPACE_CHAR eats a virtual space
6785 * BACKSPACE_WORD eats all coladd
6786 * BACKSPACE_LINE eats all coladd and keeps going
6787 */
6788 if (curwin->w_cursor.coladd > 0)
6789 {
6790 if (mode == BACKSPACE_CHAR)
6791 {
6792 --curwin->w_cursor.coladd;
6793 return TRUE;
6794 }
6795 if (mode == BACKSPACE_WORD)
6796 {
6797 curwin->w_cursor.coladd = 0;
6798 return TRUE;
6799 }
6800 curwin->w_cursor.coladd = 0;
6801 }
6802#endif
6803
6804 /*
6805 * delete newline!
6806 */
6807 if (curwin->w_cursor.col == 0)
6808 {
6809 lnum = Insstart.lnum;
6810 if (curwin->w_cursor.lnum == Insstart.lnum
6811#ifdef FEAT_RIGHTLEFT
6812 || revins_on
6813#endif
6814 )
6815 {
6816 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
6817 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
6818 return FALSE;
6819 --Insstart.lnum;
6820 Insstart.col = MAXCOL;
6821 }
6822 /*
6823 * In replace mode:
6824 * cc < 0: NL was inserted, delete it
6825 * cc >= 0: NL was replaced, put original characters back
6826 */
6827 cc = -1;
6828 if (State & REPLACE_FLAG)
6829 cc = replace_pop(); /* returns -1 if NL was inserted */
6830 /*
6831 * In replace mode, in the line we started replacing, we only move the
6832 * cursor.
6833 */
6834 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
6835 {
6836 dec_cursor();
6837 }
6838 else
6839 {
6840#ifdef FEAT_VREPLACE
6841 if (!(State & VREPLACE_FLAG)
6842 || curwin->w_cursor.lnum > orig_line_count)
6843#endif
6844 {
6845 temp = gchar_cursor(); /* remember current char */
6846 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00006847
6848 /* When "aw" is in 'formatoptions' we must delete the space at
6849 * the end of the line, otherwise the line will be broken
6850 * again when auto-formatting. */
6851 if (has_format_option(FO_AUTO)
6852 && has_format_option(FO_WHITE_PAR))
6853 {
6854 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
6855 TRUE);
6856 int len;
6857
6858 len = STRLEN(ptr);
6859 if (len > 0 && ptr[len - 1] == ' ')
6860 ptr[len - 1] = NUL;
6861 }
6862
Bram Moolenaar071d4272004-06-13 20:20:40 +00006863 (void)do_join(FALSE);
6864 if (temp == NUL && gchar_cursor() != NUL)
6865 inc_cursor();
6866 }
6867#ifdef FEAT_VREPLACE
6868 else
6869 dec_cursor();
6870#endif
6871
6872 /*
6873 * In REPLACE mode we have to put back the text that was replaced
6874 * by the NL. On the replace stack is first a NUL-terminated
6875 * sequence of characters that were deleted and then the
6876 * characters that NL replaced.
6877 */
6878 if (State & REPLACE_FLAG)
6879 {
6880 /*
6881 * Do the next ins_char() in NORMAL state, to
6882 * prevent ins_char() from replacing characters and
6883 * avoiding showmatch().
6884 */
6885 oldState = State;
6886 State = NORMAL;
6887 /*
6888 * restore characters (blanks) deleted after cursor
6889 */
6890 while (cc > 0)
6891 {
6892 temp = curwin->w_cursor.col;
6893#ifdef FEAT_MBYTE
6894 mb_replace_pop_ins(cc);
6895#else
6896 ins_char(cc);
6897#endif
6898 curwin->w_cursor.col = temp;
6899 cc = replace_pop();
6900 }
6901 /* restore the characters that NL replaced */
6902 replace_pop_ins();
6903 State = oldState;
6904 }
6905 }
6906 did_ai = FALSE;
6907 }
6908 else
6909 {
6910 /*
6911 * Delete character(s) before the cursor.
6912 */
6913#ifdef FEAT_RIGHTLEFT
6914 if (revins_on) /* put cursor on last inserted char */
6915 dec_cursor();
6916#endif
6917 mincol = 0;
6918 /* keep indent */
6919 if (mode == BACKSPACE_LINE && curbuf->b_p_ai
6920#ifdef FEAT_RIGHTLEFT
6921 && !revins_on
6922#endif
6923 )
6924 {
6925 temp = curwin->w_cursor.col;
6926 beginline(BL_WHITE);
6927 if (curwin->w_cursor.col < (colnr_T)temp)
6928 mincol = curwin->w_cursor.col;
6929 curwin->w_cursor.col = temp;
6930 }
6931
6932 /*
6933 * Handle deleting one 'shiftwidth' or 'softtabstop'.
6934 */
6935 if ( mode == BACKSPACE_CHAR
6936 && ((p_sta && in_indent)
6937 || (curbuf->b_p_sts
6938 && (*(ml_get_cursor() - 1) == TAB
6939 || (*(ml_get_cursor() - 1) == ' '
6940 && (!*inserted_space_p
6941 || arrow_used))))))
6942 {
6943 int ts;
6944 colnr_T vcol;
6945 colnr_T want_vcol;
6946 int extra = 0;
6947
6948 *inserted_space_p = FALSE;
6949 if (p_sta)
6950 ts = curbuf->b_p_sw;
6951 else
6952 ts = curbuf->b_p_sts;
6953 /* Compute the virtual column where we want to be. Since
6954 * 'showbreak' may get in the way, need to get the last column of
6955 * the previous character. */
6956 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
6957 dec_cursor();
6958 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
6959 inc_cursor();
6960 want_vcol = (want_vcol / ts) * ts;
6961
6962 /* delete characters until we are at or before want_vcol */
6963 while (vcol > want_vcol
6964 && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
6965 {
6966 dec_cursor();
6967 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
6968 if (State & REPLACE_FLAG)
6969 {
6970 /* Don't delete characters before the insert point when in
6971 * Replace mode */
6972 if (curwin->w_cursor.lnum != Insstart.lnum
6973 || curwin->w_cursor.col >= Insstart.col)
6974 {
6975#if 0 /* what was this for? It causes problems when sw != ts. */
6976 if (State == REPLACE && (int)vcol < want_vcol)
6977 {
6978 (void)del_char(FALSE);
6979 extra = 2; /* don't pop too much */
6980 }
6981 else
6982#endif
6983 replace_do_bs();
6984 }
6985 }
6986 else
6987 (void)del_char(FALSE);
6988 }
6989
6990 /* insert extra spaces until we are at want_vcol */
6991 while (vcol < want_vcol)
6992 {
6993 /* Remember the first char we inserted */
6994 if (curwin->w_cursor.lnum == Insstart.lnum
6995 && curwin->w_cursor.col < Insstart.col)
6996 Insstart.col = curwin->w_cursor.col;
6997
6998#ifdef FEAT_VREPLACE
6999 if (State & VREPLACE_FLAG)
7000 ins_char(' ');
7001 else
7002#endif
7003 {
7004 ins_str((char_u *)" ");
7005 if ((State & REPLACE_FLAG) && extra <= 1)
7006 {
7007 if (extra)
7008 replace_push_off(NUL);
7009 else
7010 replace_push(NUL);
7011 }
7012 if (extra == 2)
7013 extra = 1;
7014 }
7015 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
7016 }
7017 }
7018
7019 /*
7020 * Delete upto starting point, start of line or previous word.
7021 */
7022 else do
7023 {
7024#ifdef FEAT_RIGHTLEFT
7025 if (!revins_on) /* put cursor on char to be deleted */
7026#endif
7027 dec_cursor();
7028
7029 /* start of word? */
7030 if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
7031 {
7032 mode = BACKSPACE_WORD_NOT_SPACE;
7033 temp = vim_iswordc(gchar_cursor());
7034 }
7035 /* end of word? */
7036 else if (mode == BACKSPACE_WORD_NOT_SPACE
7037 && (vim_isspace(cc = gchar_cursor())
7038 || vim_iswordc(cc) != temp))
7039 {
7040#ifdef FEAT_RIGHTLEFT
7041 if (!revins_on)
7042#endif
7043 inc_cursor();
7044#ifdef FEAT_RIGHTLEFT
7045 else if (State & REPLACE_FLAG)
7046 dec_cursor();
7047#endif
7048 break;
7049 }
7050 if (State & REPLACE_FLAG)
7051 replace_do_bs();
7052 else
7053 {
7054#ifdef FEAT_MBYTE
7055 if (enc_utf8 && p_deco)
7056 (void)utfc_ptr2char(ml_get_cursor(), &p1, &p2);
7057#endif
7058 (void)del_char(FALSE);
7059#ifdef FEAT_MBYTE
7060 /*
7061 * If p1 or p2 is non-zero, there are combining characters we
7062 * need to take account of. Don't back up before the base
7063 * character.
7064 */
7065 if (enc_utf8 && p_deco && (p1 != NUL || p2 != NUL))
7066 inc_cursor();
7067#endif
7068#ifdef FEAT_RIGHTLEFT
7069 if (revins_chars)
7070 {
7071 revins_chars--;
7072 revins_legal++;
7073 }
7074 if (revins_on && gchar_cursor() == NUL)
7075 break;
7076#endif
7077 }
7078 /* Just a single backspace?: */
7079 if (mode == BACKSPACE_CHAR)
7080 break;
7081 } while (
7082#ifdef FEAT_RIGHTLEFT
7083 revins_on ||
7084#endif
7085 (curwin->w_cursor.col > mincol
7086 && (curwin->w_cursor.lnum != Insstart.lnum
7087 || curwin->w_cursor.col != Insstart.col)));
7088 did_backspace = TRUE;
7089 }
7090#ifdef FEAT_SMARTINDENT
7091 did_si = FALSE;
7092 can_si = FALSE;
7093 can_si_back = FALSE;
7094#endif
7095 if (curwin->w_cursor.col <= 1)
7096 did_ai = FALSE;
7097 /*
7098 * It's a little strange to put backspaces into the redo
7099 * buffer, but it makes auto-indent a lot easier to deal
7100 * with.
7101 */
7102 AppendCharToRedobuff(c);
7103
7104 /* If deleted before the insertion point, adjust it */
7105 if (curwin->w_cursor.lnum == Insstart.lnum
7106 && curwin->w_cursor.col < Insstart.col)
7107 Insstart.col = curwin->w_cursor.col;
7108
7109 /* vi behaviour: the cursor moves backward but the character that
7110 * was there remains visible
7111 * Vim behaviour: the cursor moves backward and the character that
7112 * was there is erased from the screen.
7113 * We can emulate the vi behaviour by pretending there is a dollar
7114 * displayed even when there isn't.
7115 * --pkv Sun Jan 19 01:56:40 EST 2003 */
7116 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == 0)
7117 dollar_vcol = curwin->w_virtcol;
7118
7119 return did_backspace;
7120}
7121
7122#ifdef FEAT_MOUSE
7123 static void
7124ins_mouse(c)
7125 int c;
7126{
7127 pos_T tpos;
7128
7129# ifdef FEAT_GUI
7130 /* When GUI is active, also move/paste when 'mouse' is empty */
7131 if (!gui.in_use)
7132# endif
7133 if (!mouse_has(MOUSE_INSERT))
7134 return;
7135
7136 undisplay_dollar();
7137 tpos = curwin->w_cursor;
7138 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
7139 {
7140 start_arrow(&tpos);
7141# ifdef FEAT_CINDENT
7142 can_cindent = TRUE;
7143# endif
7144 }
7145
7146#ifdef FEAT_WINDOWS
7147 /* redraw status lines (in case another window became active) */
7148 redraw_statuslines();
7149#endif
7150}
7151
7152 static void
7153ins_mousescroll(up)
7154 int up;
7155{
7156 pos_T tpos;
7157# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7158 win_T *old_curwin;
7159# endif
7160
7161 tpos = curwin->w_cursor;
7162
7163# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7164 old_curwin = curwin;
7165
7166 /* Currently the mouse coordinates are only known in the GUI. */
7167 if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
7168 {
7169 int row, col;
7170
7171 row = mouse_row;
7172 col = mouse_col;
7173
7174 /* find the window at the pointer coordinates */
7175 curwin = mouse_find_win(&row, &col);
7176 curbuf = curwin->w_buffer;
7177 }
7178 if (curwin == old_curwin)
7179# endif
7180 undisplay_dollar();
7181
7182 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
7183 scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
7184 else
7185 scroll_redraw(up, 3L);
7186
7187# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
7188 curwin->w_redr_status = TRUE;
7189
7190 curwin = old_curwin;
7191 curbuf = curwin->w_buffer;
7192# endif
7193
7194 if (!equalpos(curwin->w_cursor, tpos))
7195 {
7196 start_arrow(&tpos);
7197# ifdef FEAT_CINDENT
7198 can_cindent = TRUE;
7199# endif
7200 }
7201}
7202#endif
7203
7204#ifdef FEAT_GUI
7205 void
7206ins_scroll()
7207{
7208 pos_T tpos;
7209
7210 undisplay_dollar();
7211 tpos = curwin->w_cursor;
7212 if (gui_do_scroll())
7213 {
7214 start_arrow(&tpos);
7215# ifdef FEAT_CINDENT
7216 can_cindent = TRUE;
7217# endif
7218 }
7219}
7220
7221 void
7222ins_horscroll()
7223{
7224 pos_T tpos;
7225
7226 undisplay_dollar();
7227 tpos = curwin->w_cursor;
7228 if (gui_do_horiz_scroll())
7229 {
7230 start_arrow(&tpos);
7231# ifdef FEAT_CINDENT
7232 can_cindent = TRUE;
7233# endif
7234 }
7235}
7236#endif
7237
7238 static void
7239ins_left()
7240{
7241 pos_T tpos;
7242
7243#ifdef FEAT_FOLDING
7244 if ((fdo_flags & FDO_HOR) && KeyTyped)
7245 foldOpenCursor();
7246#endif
7247 undisplay_dollar();
7248 tpos = curwin->w_cursor;
7249 if (oneleft() == OK)
7250 {
7251 start_arrow(&tpos);
7252#ifdef FEAT_RIGHTLEFT
7253 /* If exit reversed string, position is fixed */
7254 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
7255 revins_legal++;
7256 revins_chars++;
7257#endif
7258 }
7259
7260 /*
7261 * if 'whichwrap' set for cursor in insert mode may go to
7262 * previous line
7263 */
7264 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
7265 {
7266 start_arrow(&tpos);
7267 --(curwin->w_cursor.lnum);
7268 coladvance((colnr_T)MAXCOL);
7269 curwin->w_set_curswant = TRUE; /* so we stay at the end */
7270 }
7271 else
7272 vim_beep();
7273}
7274
7275 static void
7276ins_home(c)
7277 int c;
7278{
7279 pos_T tpos;
7280
7281#ifdef FEAT_FOLDING
7282 if ((fdo_flags & FDO_HOR) && KeyTyped)
7283 foldOpenCursor();
7284#endif
7285 undisplay_dollar();
7286 tpos = curwin->w_cursor;
7287 if (c == K_C_HOME)
7288 curwin->w_cursor.lnum = 1;
7289 curwin->w_cursor.col = 0;
7290#ifdef FEAT_VIRTUALEDIT
7291 curwin->w_cursor.coladd = 0;
7292#endif
7293 curwin->w_curswant = 0;
7294 start_arrow(&tpos);
7295}
7296
7297 static void
7298ins_end(c)
7299 int c;
7300{
7301 pos_T tpos;
7302
7303#ifdef FEAT_FOLDING
7304 if ((fdo_flags & FDO_HOR) && KeyTyped)
7305 foldOpenCursor();
7306#endif
7307 undisplay_dollar();
7308 tpos = curwin->w_cursor;
7309 if (c == K_C_END)
7310 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
7311 coladvance((colnr_T)MAXCOL);
7312 curwin->w_curswant = MAXCOL;
7313
7314 start_arrow(&tpos);
7315}
7316
7317 static void
7318ins_s_left()
7319{
7320#ifdef FEAT_FOLDING
7321 if ((fdo_flags & FDO_HOR) && KeyTyped)
7322 foldOpenCursor();
7323#endif
7324 undisplay_dollar();
7325 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
7326 {
7327 start_arrow(&curwin->w_cursor);
7328 (void)bck_word(1L, FALSE, FALSE);
7329 curwin->w_set_curswant = TRUE;
7330 }
7331 else
7332 vim_beep();
7333}
7334
7335 static void
7336ins_right()
7337{
7338#ifdef FEAT_FOLDING
7339 if ((fdo_flags & FDO_HOR) && KeyTyped)
7340 foldOpenCursor();
7341#endif
7342 undisplay_dollar();
7343 if (gchar_cursor() != NUL || virtual_active()
7344 )
7345 {
7346 start_arrow(&curwin->w_cursor);
7347 curwin->w_set_curswant = TRUE;
7348#ifdef FEAT_VIRTUALEDIT
7349 if (virtual_active())
7350 oneright();
7351 else
7352#endif
7353 {
7354#ifdef FEAT_MBYTE
7355 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007356 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00007357 else
7358#endif
7359 ++curwin->w_cursor.col;
7360 }
7361
7362#ifdef FEAT_RIGHTLEFT
7363 revins_legal++;
7364 if (revins_chars)
7365 revins_chars--;
7366#endif
7367 }
7368 /* if 'whichwrap' set for cursor in insert mode, may move the
7369 * cursor to the next line */
7370 else if (vim_strchr(p_ww, ']') != NULL
7371 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
7372 {
7373 start_arrow(&curwin->w_cursor);
7374 curwin->w_set_curswant = TRUE;
7375 ++curwin->w_cursor.lnum;
7376 curwin->w_cursor.col = 0;
7377 }
7378 else
7379 vim_beep();
7380}
7381
7382 static void
7383ins_s_right()
7384{
7385#ifdef FEAT_FOLDING
7386 if ((fdo_flags & FDO_HOR) && KeyTyped)
7387 foldOpenCursor();
7388#endif
7389 undisplay_dollar();
7390 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
7391 || gchar_cursor() != NUL)
7392 {
7393 start_arrow(&curwin->w_cursor);
7394 (void)fwd_word(1L, FALSE, 0);
7395 curwin->w_set_curswant = TRUE;
7396 }
7397 else
7398 vim_beep();
7399}
7400
7401 static void
7402ins_up(startcol)
7403 int startcol; /* when TRUE move to Insstart.col */
7404{
7405 pos_T tpos;
7406 linenr_T old_topline = curwin->w_topline;
7407#ifdef FEAT_DIFF
7408 int old_topfill = curwin->w_topfill;
7409#endif
7410
7411 undisplay_dollar();
7412 tpos = curwin->w_cursor;
7413 if (cursor_up(1L, TRUE) == OK)
7414 {
7415 if (startcol)
7416 coladvance(getvcol_nolist(&Insstart));
7417 if (old_topline != curwin->w_topline
7418#ifdef FEAT_DIFF
7419 || old_topfill != curwin->w_topfill
7420#endif
7421 )
7422 redraw_later(VALID);
7423 start_arrow(&tpos);
7424#ifdef FEAT_CINDENT
7425 can_cindent = TRUE;
7426#endif
7427 }
7428 else
7429 vim_beep();
7430}
7431
7432 static void
7433ins_pageup()
7434{
7435 pos_T tpos;
7436
7437 undisplay_dollar();
7438 tpos = curwin->w_cursor;
7439 if (onepage(BACKWARD, 1L) == OK)
7440 {
7441 start_arrow(&tpos);
7442#ifdef FEAT_CINDENT
7443 can_cindent = TRUE;
7444#endif
7445 }
7446 else
7447 vim_beep();
7448}
7449
7450 static void
7451ins_down(startcol)
7452 int startcol; /* when TRUE move to Insstart.col */
7453{
7454 pos_T tpos;
7455 linenr_T old_topline = curwin->w_topline;
7456#ifdef FEAT_DIFF
7457 int old_topfill = curwin->w_topfill;
7458#endif
7459
7460 undisplay_dollar();
7461 tpos = curwin->w_cursor;
7462 if (cursor_down(1L, TRUE) == OK)
7463 {
7464 if (startcol)
7465 coladvance(getvcol_nolist(&Insstart));
7466 if (old_topline != curwin->w_topline
7467#ifdef FEAT_DIFF
7468 || old_topfill != curwin->w_topfill
7469#endif
7470 )
7471 redraw_later(VALID);
7472 start_arrow(&tpos);
7473#ifdef FEAT_CINDENT
7474 can_cindent = TRUE;
7475#endif
7476 }
7477 else
7478 vim_beep();
7479}
7480
7481 static void
7482ins_pagedown()
7483{
7484 pos_T tpos;
7485
7486 undisplay_dollar();
7487 tpos = curwin->w_cursor;
7488 if (onepage(FORWARD, 1L) == OK)
7489 {
7490 start_arrow(&tpos);
7491#ifdef FEAT_CINDENT
7492 can_cindent = TRUE;
7493#endif
7494 }
7495 else
7496 vim_beep();
7497}
7498
7499#ifdef FEAT_DND
7500 static void
7501ins_drop()
7502{
7503 do_put('~', BACKWARD, 1L, PUT_CURSEND);
7504}
7505#endif
7506
7507/*
7508 * Handle TAB in Insert or Replace mode.
7509 * Return TRUE when the TAB needs to be inserted like a normal character.
7510 */
7511 static int
7512ins_tab()
7513{
7514 int ind;
7515 int i;
7516 int temp;
7517
7518 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
7519 Insstart_blank_vcol = get_nolist_virtcol();
7520 if (echeck_abbr(TAB + ABBR_OFF))
7521 return FALSE;
7522
7523 ind = inindent(0);
7524#ifdef FEAT_CINDENT
7525 if (ind)
7526 can_cindent = FALSE;
7527#endif
7528
7529 /*
7530 * When nothing special, insert TAB like a normal character
7531 */
7532 if (!curbuf->b_p_et
7533 && !(p_sta && ind && curbuf->b_p_ts != curbuf->b_p_sw)
7534 && curbuf->b_p_sts == 0)
7535 return TRUE;
7536
7537 if (stop_arrow() == FAIL)
7538 return TRUE;
7539
7540 did_ai = FALSE;
7541#ifdef FEAT_SMARTINDENT
7542 did_si = FALSE;
7543 can_si = FALSE;
7544 can_si_back = FALSE;
7545#endif
7546 AppendToRedobuff((char_u *)"\t");
7547
7548 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
7549 temp = (int)curbuf->b_p_sw;
7550 else if (curbuf->b_p_sts > 0) /* use 'softtabstop' when set */
7551 temp = (int)curbuf->b_p_sts;
7552 else /* otherwise use 'tabstop' */
7553 temp = (int)curbuf->b_p_ts;
7554 temp -= get_nolist_virtcol() % temp;
7555
7556 /*
7557 * Insert the first space with ins_char(). It will delete one char in
7558 * replace mode. Insert the rest with ins_str(); it will not delete any
7559 * chars. For VREPLACE mode, we use ins_char() for all characters.
7560 */
7561 ins_char(' ');
7562 while (--temp > 0)
7563 {
7564#ifdef FEAT_VREPLACE
7565 if (State & VREPLACE_FLAG)
7566 ins_char(' ');
7567 else
7568#endif
7569 {
7570 ins_str((char_u *)" ");
7571 if (State & REPLACE_FLAG) /* no char replaced */
7572 replace_push(NUL);
7573 }
7574 }
7575
7576 /*
7577 * When 'expandtab' not set: Replace spaces by TABs where possible.
7578 */
7579 if (!curbuf->b_p_et && (curbuf->b_p_sts || (p_sta && ind)))
7580 {
7581 char_u *ptr;
7582#ifdef FEAT_VREPLACE
7583 char_u *saved_line = NULL; /* init for GCC */
7584 pos_T pos;
7585#endif
7586 pos_T fpos;
7587 pos_T *cursor;
7588 colnr_T want_vcol, vcol;
7589 int change_col = -1;
7590 int save_list = curwin->w_p_list;
7591
7592 /*
7593 * Get the current line. For VREPLACE mode, don't make real changes
7594 * yet, just work on a copy of the line.
7595 */
7596#ifdef FEAT_VREPLACE
7597 if (State & VREPLACE_FLAG)
7598 {
7599 pos = curwin->w_cursor;
7600 cursor = &pos;
7601 saved_line = vim_strsave(ml_get_curline());
7602 if (saved_line == NULL)
7603 return FALSE;
7604 ptr = saved_line + pos.col;
7605 }
7606 else
7607#endif
7608 {
7609 ptr = ml_get_cursor();
7610 cursor = &curwin->w_cursor;
7611 }
7612
7613 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
7614 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
7615 curwin->w_p_list = FALSE;
7616
7617 /* Find first white before the cursor */
7618 fpos = curwin->w_cursor;
7619 while (fpos.col > 0 && vim_iswhite(ptr[-1]))
7620 {
7621 --fpos.col;
7622 --ptr;
7623 }
7624
7625 /* In Replace mode, don't change characters before the insert point. */
7626 if ((State & REPLACE_FLAG)
7627 && fpos.lnum == Insstart.lnum
7628 && fpos.col < Insstart.col)
7629 {
7630 ptr += Insstart.col - fpos.col;
7631 fpos.col = Insstart.col;
7632 }
7633
7634 /* compute virtual column numbers of first white and cursor */
7635 getvcol(curwin, &fpos, &vcol, NULL, NULL);
7636 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
7637
7638 /* Use as many TABs as possible. Beware of 'showbreak' and
7639 * 'linebreak' adding extra virtual columns. */
7640 while (vim_iswhite(*ptr))
7641 {
7642 i = lbr_chartabsize((char_u *)"\t", vcol);
7643 if (vcol + i > want_vcol)
7644 break;
7645 if (*ptr != TAB)
7646 {
7647 *ptr = TAB;
7648 if (change_col < 0)
7649 {
7650 change_col = fpos.col; /* Column of first change */
7651 /* May have to adjust Insstart */
7652 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
7653 Insstart.col = fpos.col;
7654 }
7655 }
7656 ++fpos.col;
7657 ++ptr;
7658 vcol += i;
7659 }
7660
7661 if (change_col >= 0)
7662 {
7663 int repl_off = 0;
7664
7665 /* Skip over the spaces we need. */
7666 while (vcol < want_vcol && *ptr == ' ')
7667 {
7668 vcol += lbr_chartabsize(ptr, vcol);
7669 ++ptr;
7670 ++repl_off;
7671 }
7672 if (vcol > want_vcol)
7673 {
7674 /* Must have a char with 'showbreak' just before it. */
7675 --ptr;
7676 --repl_off;
7677 }
7678 fpos.col += repl_off;
7679
7680 /* Delete following spaces. */
7681 i = cursor->col - fpos.col;
7682 if (i > 0)
7683 {
7684 mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
7685 /* correct replace stack. */
7686 if ((State & REPLACE_FLAG)
7687#ifdef FEAT_VREPLACE
7688 && !(State & VREPLACE_FLAG)
7689#endif
7690 )
7691 for (temp = i; --temp >= 0; )
7692 replace_join(repl_off);
7693 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00007694#ifdef FEAT_NETBEANS_INTG
7695 if (usingNetbeans)
7696 {
7697 netbeans_removed(curbuf, fpos.lnum, cursor->col,
7698 (long)(i + 1));
7699 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
7700 (char_u *)"\t", 1);
7701 }
7702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007703 cursor->col -= i;
7704
7705#ifdef FEAT_VREPLACE
7706 /*
7707 * In VREPLACE mode, we haven't changed anything yet. Do it now by
7708 * backspacing over the changed spacing and then inserting the new
7709 * spacing.
7710 */
7711 if (State & VREPLACE_FLAG)
7712 {
7713 /* Backspace from real cursor to change_col */
7714 backspace_until_column(change_col);
7715
7716 /* Insert each char in saved_line from changed_col to
7717 * ptr-cursor */
7718 ins_bytes_len(saved_line + change_col,
7719 cursor->col - change_col);
7720 }
7721#endif
7722 }
7723
7724#ifdef FEAT_VREPLACE
7725 if (State & VREPLACE_FLAG)
7726 vim_free(saved_line);
7727#endif
7728 curwin->w_p_list = save_list;
7729 }
7730
7731 return FALSE;
7732}
7733
7734/*
7735 * Handle CR or NL in insert mode.
7736 * Return TRUE when out of memory or can't undo.
7737 */
7738 static int
7739ins_eol(c)
7740 int c;
7741{
7742 int i;
7743
7744 if (echeck_abbr(c + ABBR_OFF))
7745 return FALSE;
7746 if (stop_arrow() == FAIL)
7747 return TRUE;
7748 undisplay_dollar();
7749
7750 /*
7751 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
7752 * character under the cursor. Only push a NUL on the replace stack,
7753 * nothing to put back when the NL is deleted.
7754 */
7755 if ((State & REPLACE_FLAG)
7756#ifdef FEAT_VREPLACE
7757 && !(State & VREPLACE_FLAG)
7758#endif
7759 )
7760 replace_push(NUL);
7761
7762 /*
7763 * In VREPLACE mode, a NL replaces the rest of the line, and starts
7764 * replacing the next line, so we push all of the characters left on the
7765 * line onto the replace stack. This is not done here though, it is done
7766 * in open_line().
7767 */
7768
7769#ifdef FEAT_RIGHTLEFT
7770# ifdef FEAT_FKMAP
7771 if (p_altkeymap && p_fkmap)
7772 fkmap(NL);
7773# endif
7774 /* NL in reverse insert will always start in the end of
7775 * current line. */
7776 if (revins_on)
7777 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
7778#endif
7779
7780 AppendToRedobuff(NL_STR);
7781 i = open_line(FORWARD,
7782#ifdef FEAT_COMMENTS
7783 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
7784#endif
7785 0, old_indent);
7786 old_indent = 0;
7787#ifdef FEAT_CINDENT
7788 can_cindent = TRUE;
7789#endif
7790
7791 return (!i);
7792}
7793
7794#ifdef FEAT_DIGRAPHS
7795/*
7796 * Handle digraph in insert mode.
7797 * Returns character still to be inserted, or NUL when nothing remaining to be
7798 * done.
7799 */
7800 static int
7801ins_digraph()
7802{
7803 int c;
7804 int cc;
7805
7806 pc_status = PC_STATUS_UNSET;
7807 if (redrawing() && !char_avail())
7808 {
7809 /* may need to redraw when no more chars available now */
7810 ins_redraw();
7811
7812 edit_putchar('?', TRUE);
7813#ifdef FEAT_CMDL_INFO
7814 add_to_showcmd_c(Ctrl_K);
7815#endif
7816 }
7817
7818#ifdef USE_ON_FLY_SCROLL
7819 dont_scroll = TRUE; /* disallow scrolling here */
7820#endif
7821
7822 /* don't map the digraph chars. This also prevents the
7823 * mode message to be deleted when ESC is hit */
7824 ++no_mapping;
7825 ++allow_keys;
7826 c = safe_vgetc();
7827 --no_mapping;
7828 --allow_keys;
7829 if (IS_SPECIAL(c) || mod_mask) /* special key */
7830 {
7831#ifdef FEAT_CMDL_INFO
7832 clear_showcmd();
7833#endif
7834 insert_special(c, TRUE, FALSE);
7835 return NUL;
7836 }
7837 if (c != ESC)
7838 {
7839 if (redrawing() && !char_avail())
7840 {
7841 /* may need to redraw when no more chars available now */
7842 ins_redraw();
7843
7844 if (char2cells(c) == 1)
7845 {
7846 /* first remove the '?', otherwise it's restored when typing
7847 * an ESC next */
7848 edit_unputchar();
7849 ins_redraw();
7850 edit_putchar(c, TRUE);
7851 }
7852#ifdef FEAT_CMDL_INFO
7853 add_to_showcmd_c(c);
7854#endif
7855 }
7856 ++no_mapping;
7857 ++allow_keys;
7858 cc = safe_vgetc();
7859 --no_mapping;
7860 --allow_keys;
7861 if (cc != ESC)
7862 {
7863 AppendToRedobuff((char_u *)CTRL_V_STR);
7864 c = getdigraph(c, cc, TRUE);
7865#ifdef FEAT_CMDL_INFO
7866 clear_showcmd();
7867#endif
7868 return c;
7869 }
7870 }
7871 edit_unputchar();
7872#ifdef FEAT_CMDL_INFO
7873 clear_showcmd();
7874#endif
7875 return NUL;
7876}
7877#endif
7878
7879/*
7880 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
7881 * Returns the char to be inserted, or NUL if none found.
7882 */
7883 static int
7884ins_copychar(lnum)
7885 linenr_T lnum;
7886{
7887 int c;
7888 int temp;
7889 char_u *ptr, *prev_ptr;
7890
7891 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7892 {
7893 vim_beep();
7894 return NUL;
7895 }
7896
7897 /* try to advance to the cursor column */
7898 temp = 0;
7899 ptr = ml_get(lnum);
7900 prev_ptr = ptr;
7901 validate_virtcol();
7902 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
7903 {
7904 prev_ptr = ptr;
7905 temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
7906 }
7907 if ((colnr_T)temp > curwin->w_virtcol)
7908 ptr = prev_ptr;
7909
7910#ifdef FEAT_MBYTE
7911 c = (*mb_ptr2char)(ptr);
7912#else
7913 c = *ptr;
7914#endif
7915 if (c == NUL)
7916 vim_beep();
7917 return c;
7918}
7919
Bram Moolenaar4be06f92005-07-29 22:36:03 +00007920/*
7921 * CTRL-Y or CTRL-E typed in Insert mode.
7922 */
7923 static int
7924ins_ctrl_ey(tc)
7925 int tc;
7926{
7927 int c = tc;
7928
7929#ifdef FEAT_INS_EXPAND
7930 if (ctrl_x_mode == CTRL_X_SCROLL)
7931 {
7932 if (c == Ctrl_Y)
7933 scrolldown_clamp();
7934 else
7935 scrollup_clamp();
7936 redraw_later(VALID);
7937 }
7938 else
7939#endif
7940 {
7941 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
7942 if (c != NUL)
7943 {
7944 long tw_save;
7945
7946 /* The character must be taken literally, insert like it
7947 * was typed after a CTRL-V, and pretend 'textwidth'
7948 * wasn't set. Digits, 'o' and 'x' are special after a
7949 * CTRL-V, don't use it for these. */
7950 if (c < 256 && !isalnum(c))
7951 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
7952 tw_save = curbuf->b_p_tw;
7953 curbuf->b_p_tw = -1;
7954 insert_special(c, TRUE, FALSE);
7955 curbuf->b_p_tw = tw_save;
7956#ifdef FEAT_RIGHTLEFT
7957 revins_chars++;
7958 revins_legal++;
7959#endif
7960 c = Ctrl_V; /* pretend CTRL-V is last character */
7961 auto_format(FALSE, TRUE);
7962 }
7963 }
7964 return c;
7965}
7966
Bram Moolenaar071d4272004-06-13 20:20:40 +00007967#ifdef FEAT_SMARTINDENT
7968/*
7969 * Try to do some very smart auto-indenting.
7970 * Used when inserting a "normal" character.
7971 */
7972 static void
7973ins_try_si(c)
7974 int c;
7975{
7976 pos_T *pos, old_pos;
7977 char_u *ptr;
7978 int i;
7979 int temp;
7980
7981 /*
7982 * do some very smart indenting when entering '{' or '}'
7983 */
7984 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
7985 {
7986 /*
7987 * for '}' set indent equal to indent of line containing matching '{'
7988 */
7989 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
7990 {
7991 old_pos = curwin->w_cursor;
7992 /*
7993 * If the matching '{' has a ')' immediately before it (ignoring
7994 * white-space), then line up with the start of the line
7995 * containing the matching '(' if there is one. This handles the
7996 * case where an "if (..\n..) {" statement continues over multiple
7997 * lines -- webb
7998 */
7999 ptr = ml_get(pos->lnum);
8000 i = pos->col;
8001 if (i > 0) /* skip blanks before '{' */
8002 while (--i > 0 && vim_iswhite(ptr[i]))
8003 ;
8004 curwin->w_cursor.lnum = pos->lnum;
8005 curwin->w_cursor.col = i;
8006 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
8007 curwin->w_cursor = *pos;
8008 i = get_indent();
8009 curwin->w_cursor = old_pos;
8010#ifdef FEAT_VREPLACE
8011 if (State & VREPLACE_FLAG)
8012 change_indent(INDENT_SET, i, FALSE, NUL);
8013 else
8014#endif
8015 (void)set_indent(i, SIN_CHANGED);
8016 }
8017 else if (curwin->w_cursor.col > 0)
8018 {
8019 /*
8020 * when inserting '{' after "O" reduce indent, but not
8021 * more than indent of previous line
8022 */
8023 temp = TRUE;
8024 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
8025 {
8026 old_pos = curwin->w_cursor;
8027 i = get_indent();
8028 while (curwin->w_cursor.lnum > 1)
8029 {
8030 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
8031
8032 /* ignore empty lines and lines starting with '#'. */
8033 if (*ptr != '#' && *ptr != NUL)
8034 break;
8035 }
8036 if (get_indent() >= i)
8037 temp = FALSE;
8038 curwin->w_cursor = old_pos;
8039 }
8040 if (temp)
8041 shift_line(TRUE, FALSE, 1);
8042 }
8043 }
8044
8045 /*
8046 * set indent of '#' always to 0
8047 */
8048 if (curwin->w_cursor.col > 0 && can_si && c == '#')
8049 {
8050 /* remember current indent for next line */
8051 old_indent = get_indent();
8052 (void)set_indent(0, SIN_CHANGED);
8053 }
8054
8055 /* Adjust ai_col, the char at this position can be deleted. */
8056 if (ai_col > curwin->w_cursor.col)
8057 ai_col = curwin->w_cursor.col;
8058}
8059#endif
8060
8061/*
8062 * Get the value that w_virtcol would have when 'list' is off.
8063 * Unless 'cpo' contains the 'L' flag.
8064 */
8065 static colnr_T
8066get_nolist_virtcol()
8067{
8068 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8069 return getvcol_nolist(&curwin->w_cursor);
8070 validate_virtcol();
8071 return curwin->w_virtcol;
8072}