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