blob: 782bdbee01a2d01a16bfdc0cc8efd39c30acaa86 [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 * getchar.c
12 *
13 * functions related with getting a character from the user/mapping/redo/...
14 *
15 * manipulations with redo buffer and stuff buffer
16 * mappings and abbreviations
17 */
18
19#include "vim.h"
20
21/*
22 * These buffers are used for storing:
23 * - stuffed characters: A command that is translated into another command.
24 * - redo characters: will redo the last change.
25 * - recorded chracters: for the "q" command.
26 *
27 * The bytes are stored like in the typeahead buffer:
28 * - K_SPECIAL introduces a special key (two more bytes follow). A literal
29 * K_SPECIAL is stored as K_SPECIAL KS_SPECIAL KE_FILLER.
30 * - CSI introduces a GUI termcap code (also when gui.in_use is FALSE,
31 * otherwise switching the GUI on would make mappings invalid).
32 * A literal CSI is stored as CSI KS_EXTRA KE_CSI.
33 * These translations are also done on multi-byte characters!
34 *
35 * Escaping CSI bytes is done by the system-specific input functions, called
36 * by ui_inchar().
37 * Escaping K_SPECIAL is done by inchar().
38 * Un-escaping is done by vgetc().
39 */
40
41#define MINIMAL_SIZE 20 /* minimal size for b_str */
42
43static struct buffheader redobuff = {{NULL, {NUL}}, NULL, 0, 0};
44static struct buffheader old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
45#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
46static struct buffheader save_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
47static struct buffheader save_old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
48#endif
49static struct buffheader recordbuff = {{NULL, {NUL}}, NULL, 0, 0};
50
51static int typeahead_char = 0; /* typeahead char that's not flushed */
52
53/*
54 * when block_redo is TRUE redo buffer will not be changed
55 * used by edit() to repeat insertions and 'V' command for redoing
56 */
57static int block_redo = FALSE;
58
59/*
60 * Make a hash value for a mapping.
61 * "mode" is the lower 4 bits of the State for the mapping.
62 * "c1" is the first character of the "lhs".
63 * Returns a value between 0 and 255, index in maphash.
64 * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
65 */
Bram Moolenaar371d5402006-03-20 21:47:49 +000066#define MAP_HASH(mode, c1) (((mode) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING)) ? (c1) : ((c1) ^ 0x80))
Bram Moolenaar071d4272004-06-13 20:20:40 +000067
68/*
69 * Each mapping is put in one of the 256 hash lists, to speed up finding it.
70 */
71static mapblock_T *(maphash[256]);
72static int maphash_valid = FALSE;
73
74/*
75 * List used for abbreviations.
76 */
77static mapblock_T *first_abbr = NULL; /* first entry in abbrlist */
78
79static int KeyNoremap = FALSE; /* remapping disabled */
80
81/*
82 * variables used by vgetorpeek() and flush_buffers()
83 *
84 * typebuf.tb_buf[] contains all characters that are not consumed yet.
85 * typebuf.tb_buf[typebuf.tb_off] is the first valid character.
86 * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char.
87 * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL.
88 * The head of the buffer may contain the result of mappings, abbreviations
89 * and @a commands. The length of this part is typebuf.tb_maplen.
90 * typebuf.tb_silent is the part where <silent> applies.
91 * After the head are characters that come from the terminal.
92 * typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that
93 * should not be considered for abbreviations.
94 * Some parts of typebuf.tb_buf may not be mapped. These parts are remembered
95 * in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and
96 * contains RM_NONE for the characters that are not to be remapped.
97 * typebuf.tb_noremap[typebuf.tb_off] is the first valid flag.
98 * (typebuf has been put in globals.h, because check_termcode() needs it).
99 */
100#define RM_YES 0 /* tb_noremap: remap */
101#define RM_NONE 1 /* tb_noremap: don't remap */
102#define RM_SCRIPT 2 /* tb_noremap: remap local script mappings */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000103#define RM_ABBR 4 /* tb_noremap: don't remap, do abbrev. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104
105/* typebuf.tb_buf has three parts: room in front (for result of mappings), the
106 * middle for typeahead and room for new characters (which needs to be 3 *
107 * MAXMAPLEN) for the Amiga).
108 */
109#define TYPELEN_INIT (5 * (MAXMAPLEN + 3))
110static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
111static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
112
113static int last_recorded_len = 0; /* number of last recorded chars */
114
115static char_u *get_buffcont __ARGS((struct buffheader *, int));
116static void add_buff __ARGS((struct buffheader *, char_u *, long n));
117static void add_num_buff __ARGS((struct buffheader *, long));
118static void add_char_buff __ARGS((struct buffheader *, int));
119static int read_stuff __ARGS((int advance));
120static void start_stuff __ARGS((void));
121static int read_redo __ARGS((int, int));
122static void copy_redo __ARGS((int));
123static void init_typebuf __ARGS((void));
124static void gotchars __ARGS((char_u *, int));
125static void may_sync_undo __ARGS((void));
126static void closescript __ARGS((void));
127static int vgetorpeek __ARGS((int));
128static void map_free __ARGS((mapblock_T **));
129static void validate_maphash __ARGS((void));
130static void showmap __ARGS((mapblock_T *mp, int local));
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000131#ifdef FEAT_EVAL
132static char_u *eval_map_expr __ARGS((char_u *str));
133#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135/*
136 * Free and clear a buffer.
137 */
138 void
139free_buff(buf)
140 struct buffheader *buf;
141{
142 struct buffblock *p, *np;
143
144 for (p = buf->bh_first.b_next; p != NULL; p = np)
145 {
146 np = p->b_next;
147 vim_free(p);
148 }
149 buf->bh_first.b_next = NULL;
150}
151
152/*
153 * Return the contents of a buffer as a single string.
154 * K_SPECIAL and CSI in the returned string are escaped.
155 */
156 static char_u *
157get_buffcont(buffer, dozero)
158 struct buffheader *buffer;
159 int dozero; /* count == zero is not an error */
160{
161 long_u count = 0;
162 char_u *p = NULL;
163 char_u *p2;
164 char_u *str;
165 struct buffblock *bp;
166
167 /* compute the total length of the string */
168 for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
169 count += (long_u)STRLEN(bp->b_str);
170
171 if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL)
172 {
173 p2 = p;
174 for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
175 for (str = bp->b_str; *str; )
176 *p2++ = *str++;
177 *p2 = NUL;
178 }
179 return (p);
180}
181
182/*
183 * Return the contents of the record buffer as a single string
184 * and clear the record buffer.
185 * K_SPECIAL and CSI in the returned string are escaped.
186 */
187 char_u *
188get_recorded()
189{
190 char_u *p;
191 size_t len;
192
193 p = get_buffcont(&recordbuff, TRUE);
194 free_buff(&recordbuff);
195
196 /*
197 * Remove the characters that were added the last time, these must be the
198 * (possibly mapped) characters that stopped the recording.
199 */
200 len = STRLEN(p);
201 if ((int)len >= last_recorded_len)
202 {
203 len -= last_recorded_len;
204 p[len] = NUL;
205 }
206
207 /*
208 * When stopping recording from Insert mode with CTRL-O q, also remove the
209 * CTRL-O.
210 */
211 if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O)
212 p[len - 1] = NUL;
213
214 return (p);
215}
216
217/*
218 * Return the contents of the redo buffer as a single string.
219 * K_SPECIAL and CSI in the returned string are escaped.
220 */
221 char_u *
222get_inserted()
223{
224 return(get_buffcont(&redobuff, FALSE));
225}
226
227/*
228 * add string "s" after the current block of buffer "buf"
229 * K_SPECIAL and CSI should have been escaped already.
230 */
231 static void
232add_buff(buf, s, slen)
233 struct buffheader *buf;
234 char_u *s;
235 long slen; /* length of "s" or -1 */
236{
237 struct buffblock *p;
238 long_u len;
239
240 if (slen < 0)
241 slen = (long)STRLEN(s);
242 if (slen == 0) /* don't add empty strings */
243 return;
244
245 if (buf->bh_first.b_next == NULL) /* first add to list */
246 {
247 buf->bh_space = 0;
248 buf->bh_curr = &(buf->bh_first);
249 }
250 else if (buf->bh_curr == NULL) /* buffer has already been read */
251 {
252 EMSG(_("E222: Add to read buffer"));
253 return;
254 }
255 else if (buf->bh_index != 0)
256 STRCPY(buf->bh_first.b_next->b_str,
257 buf->bh_first.b_next->b_str + buf->bh_index);
258 buf->bh_index = 0;
259
260 if (buf->bh_space >= (int)slen)
261 {
262 len = (long_u)STRLEN(buf->bh_curr->b_str);
Bram Moolenaarb6356332005-07-18 21:40:44 +0000263 vim_strncpy(buf->bh_curr->b_str + len, s, (size_t)slen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 buf->bh_space -= slen;
265 }
266 else
267 {
268 if (slen < MINIMAL_SIZE)
269 len = MINIMAL_SIZE;
270 else
271 len = slen;
272 p = (struct buffblock *)lalloc((long_u)(sizeof(struct buffblock) + len),
273 TRUE);
274 if (p == NULL)
275 return; /* no space, just forget it */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000276 buf->bh_space = (int)(len - slen);
Bram Moolenaarb6356332005-07-18 21:40:44 +0000277 vim_strncpy(p->b_str, s, (size_t)slen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278
279 p->b_next = buf->bh_curr->b_next;
280 buf->bh_curr->b_next = p;
281 buf->bh_curr = p;
282 }
283 return;
284}
285
286/*
287 * Add number "n" to buffer "buf".
288 */
289 static void
290add_num_buff(buf, n)
291 struct buffheader *buf;
292 long n;
293{
294 char_u number[32];
295
296 sprintf((char *)number, "%ld", n);
297 add_buff(buf, number, -1L);
298}
299
300/*
301 * Add character 'c' to buffer "buf".
302 * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
303 */
304 static void
305add_char_buff(buf, c)
306 struct buffheader *buf;
307 int c;
308{
309#ifdef FEAT_MBYTE
310 char_u bytes[MB_MAXBYTES + 1];
311 int len;
312 int i;
313#endif
314 char_u temp[4];
315
316#ifdef FEAT_MBYTE
317 if (IS_SPECIAL(c))
318 len = 1;
319 else
320 len = (*mb_char2bytes)(c, bytes);
321 for (i = 0; i < len; ++i)
322 {
323 if (!IS_SPECIAL(c))
324 c = bytes[i];
325#endif
326
327 if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL)
328 {
329 /* translate special key code into three byte sequence */
330 temp[0] = K_SPECIAL;
331 temp[1] = K_SECOND(c);
332 temp[2] = K_THIRD(c);
333 temp[3] = NUL;
334 }
335#ifdef FEAT_GUI
336 else if (c == CSI)
337 {
338 /* Translate a CSI to a CSI - KS_EXTRA - KE_CSI sequence */
339 temp[0] = CSI;
340 temp[1] = KS_EXTRA;
341 temp[2] = (int)KE_CSI;
342 temp[3] = NUL;
343 }
344#endif
345 else
346 {
347 temp[0] = c;
348 temp[1] = NUL;
349 }
350 add_buff(buf, temp, -1L);
351#ifdef FEAT_MBYTE
352 }
353#endif
354}
355
356/*
357 * Get one byte from the stuff buffer.
358 * If advance == TRUE go to the next char.
359 * No translation is done K_SPECIAL and CSI are escaped.
360 */
361 static int
362read_stuff(advance)
363 int advance;
364{
365 char_u c;
366 struct buffblock *curr;
367
368 if (stuffbuff.bh_first.b_next == NULL) /* buffer is empty */
369 return NUL;
370
371 curr = stuffbuff.bh_first.b_next;
372 c = curr->b_str[stuffbuff.bh_index];
373
374 if (advance)
375 {
376 if (curr->b_str[++stuffbuff.bh_index] == NUL)
377 {
378 stuffbuff.bh_first.b_next = curr->b_next;
379 vim_free(curr);
380 stuffbuff.bh_index = 0;
381 }
382 }
383 return c;
384}
385
386/*
387 * Prepare the stuff buffer for reading (if it contains something).
388 */
389 static void
390start_stuff()
391{
392 if (stuffbuff.bh_first.b_next != NULL)
393 {
394 stuffbuff.bh_curr = &(stuffbuff.bh_first);
395 stuffbuff.bh_space = 0;
396 }
397}
398
399/*
400 * Return TRUE if the stuff buffer is empty.
401 */
402 int
403stuff_empty()
404{
405 return (stuffbuff.bh_first.b_next == NULL);
406}
407
408/*
409 * Set a typeahead character that won't be flushed.
410 */
411 void
412typeahead_noflush(c)
413 int c;
414{
415 typeahead_char = c;
416}
417
418/*
419 * Remove the contents of the stuff buffer and the mapped characters in the
420 * typeahead buffer (used in case of an error). If 'typeahead' is true,
421 * flush all typeahead characters (used when interrupted by a CTRL-C).
422 */
423 void
424flush_buffers(typeahead)
425 int typeahead;
426{
427 init_typebuf();
428
429 start_stuff();
430 while (read_stuff(TRUE) != NUL)
431 ;
432
433 if (typeahead) /* remove all typeahead */
434 {
435 /*
436 * We have to get all characters, because we may delete the first part
437 * of an escape sequence.
438 * In an xterm we get one char at a time and we have to get them all.
439 */
440 while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L,
441 typebuf.tb_change_cnt) != 0)
442 ;
443 typebuf.tb_off = MAXMAPLEN;
444 typebuf.tb_len = 0;
445 }
446 else /* remove mapped characters only */
447 {
448 typebuf.tb_off += typebuf.tb_maplen;
449 typebuf.tb_len -= typebuf.tb_maplen;
450 }
451 typebuf.tb_maplen = 0;
452 typebuf.tb_silent = 0;
453 cmd_silent = FALSE;
454 typebuf.tb_no_abbr_cnt = 0;
455}
456
457/*
458 * The previous contents of the redo buffer is kept in old_redobuffer.
459 * This is used for the CTRL-O <.> command in insert mode.
460 */
461 void
462ResetRedobuff()
463{
464 if (!block_redo)
465 {
466 free_buff(&old_redobuff);
467 old_redobuff = redobuff;
468 redobuff.bh_first.b_next = NULL;
469 }
470}
471
472#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
473/*
474 * Save redobuff and old_redobuff to save_redobuff and save_old_redobuff.
475 * Used before executing autocommands and user functions.
476 */
477static int save_level = 0;
478
479 void
480saveRedobuff()
481{
482 char_u *s;
483
484 if (save_level++ == 0)
485 {
486 save_redobuff = redobuff;
487 redobuff.bh_first.b_next = NULL;
488 save_old_redobuff = old_redobuff;
489 old_redobuff.bh_first.b_next = NULL;
490
491 /* Make a copy, so that ":normal ." in a function works. */
492 s = get_buffcont(&save_redobuff, FALSE);
493 if (s != NULL)
494 {
495 add_buff(&redobuff, s, -1L);
496 vim_free(s);
497 }
498 }
499}
500
501/*
502 * Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff.
503 * Used after executing autocommands and user functions.
504 */
505 void
506restoreRedobuff()
507{
508 if (--save_level == 0)
509 {
510 free_buff(&redobuff);
511 redobuff = save_redobuff;
512 free_buff(&old_redobuff);
513 old_redobuff = save_old_redobuff;
514 }
515}
516#endif
517
518/*
519 * Append "s" to the redo buffer.
520 * K_SPECIAL and CSI should already have been escaped.
521 */
522 void
523AppendToRedobuff(s)
524 char_u *s;
525{
526 if (!block_redo)
527 add_buff(&redobuff, s, -1L);
528}
529
530/*
531 * Append to Redo buffer literally, escaping special characters with CTRL-V.
532 * K_SPECIAL and CSI are escaped as well.
533 */
534 void
Bram Moolenaarebefac62005-12-28 22:39:57 +0000535AppendToRedobuffLit(str, len)
536 char_u *str;
537 int len; /* length of "str" or -1 for up to the NUL */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000538{
Bram Moolenaarebefac62005-12-28 22:39:57 +0000539 char_u *s = str;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 int c;
541 char_u *start;
542
543 if (block_redo)
544 return;
545
Bram Moolenaarebefac62005-12-28 22:39:57 +0000546 while (len < 0 ? *s != NUL : s - str < len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 {
548 /* Put a string of normal characters in the redo buffer (that's
549 * faster). */
550 start = s;
551 while (*s >= ' '
552#ifndef EBCDIC
553 && *s < DEL /* EBCDIC: all chars above space are normal */
554#endif
Bram Moolenaarebefac62005-12-28 22:39:57 +0000555 && (len < 0 || s - str < len))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 ++s;
557
558 /* Don't put '0' or '^' as last character, just in case a CTRL-D is
559 * typed next. */
560 if (*s == NUL && (s[-1] == '0' || s[-1] == '^'))
561 --s;
562 if (s > start)
563 add_buff(&redobuff, start, (long)(s - start));
564
Bram Moolenaarebefac62005-12-28 22:39:57 +0000565 if (*s == NUL || (len >= 0 && s - str >= len))
566 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567
Bram Moolenaarebefac62005-12-28 22:39:57 +0000568 /* Handle a special or multibyte character. */
569#ifdef FEAT_MBYTE
570 if (has_mbyte)
571 /* Handle composing chars separately. */
572 c = mb_cptr2char_adv(&s);
573 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574#endif
Bram Moolenaarebefac62005-12-28 22:39:57 +0000575 c = *s++;
576 if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^')))
577 add_char_buff(&redobuff, Ctrl_V);
578
579 /* CTRL-V '0' must be inserted as CTRL-V 048 (EBCDIC: xf0) */
580 if (*s == NUL && c == '0')
581#ifdef EBCDIC
582 add_buff(&redobuff, (char_u *)"xf0", 3L);
583#else
584 add_buff(&redobuff, (char_u *)"048", 3L);
585#endif
586 else
587 add_char_buff(&redobuff, c);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 }
589}
590
591/*
592 * Append a character to the redo buffer.
593 * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
594 */
595 void
596AppendCharToRedobuff(c)
597 int c;
598{
599 if (!block_redo)
600 add_char_buff(&redobuff, c);
601}
602
603/*
604 * Append a number to the redo buffer.
605 */
606 void
607AppendNumberToRedobuff(n)
608 long n;
609{
610 if (!block_redo)
611 add_num_buff(&redobuff, n);
612}
613
614/*
615 * Append string "s" to the stuff buffer.
616 * CSI and K_SPECIAL must already have been escaped.
617 */
618 void
619stuffReadbuff(s)
620 char_u *s;
621{
622 add_buff(&stuffbuff, s, -1L);
623}
624
625 void
626stuffReadbuffLen(s, len)
627 char_u *s;
628 long len;
629{
630 add_buff(&stuffbuff, s, len);
631}
632
633#if defined(FEAT_EVAL) || defined(PROTO)
634/*
635 * Stuff "s" into the stuff buffer, leaving special key codes unmodified and
636 * escaping other K_SPECIAL and CSI bytes.
637 */
638 void
639stuffReadbuffSpec(s)
640 char_u *s;
641{
642 while (*s != NUL)
643 {
644 if (*s == K_SPECIAL && s[1] != NUL && s[2] != NUL)
645 {
646 /* Insert special key literally. */
647 stuffReadbuffLen(s, 3L);
648 s += 3;
649 }
650 else
651#ifdef FEAT_MBYTE
652 stuffcharReadbuff(mb_ptr2char_adv(&s));
653#else
654 stuffcharReadbuff(*s++);
655#endif
656 }
657}
658#endif
659
660/*
661 * Append a character to the stuff buffer.
662 * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
663 */
664 void
665stuffcharReadbuff(c)
666 int c;
667{
668 add_char_buff(&stuffbuff, c);
669}
670
671/*
672 * Append a number to the stuff buffer.
673 */
674 void
675stuffnumReadbuff(n)
676 long n;
677{
678 add_num_buff(&stuffbuff, n);
679}
680
681/*
682 * Read a character from the redo buffer. Translates K_SPECIAL, CSI and
683 * multibyte characters.
684 * The redo buffer is left as it is.
685 * if init is TRUE, prepare for redo, return FAIL if nothing to redo, OK
686 * otherwise
687 * if old is TRUE, use old_redobuff instead of redobuff
688 */
689 static int
690read_redo(init, old_redo)
691 int init;
692 int old_redo;
693{
694 static struct buffblock *bp;
695 static char_u *p;
696 int c;
697#ifdef FEAT_MBYTE
698 int n;
699 char_u buf[MB_MAXBYTES];
700 int i;
701#endif
702
703 if (init)
704 {
705 if (old_redo)
706 bp = old_redobuff.bh_first.b_next;
707 else
708 bp = redobuff.bh_first.b_next;
709 if (bp == NULL)
710 return FAIL;
711 p = bp->b_str;
712 return OK;
713 }
714 if ((c = *p) != NUL)
715 {
716 /* Reverse the conversion done by add_char_buff() */
717#ifdef FEAT_MBYTE
718 /* For a multi-byte character get all the bytes and return the
719 * converted character. */
720 if (has_mbyte && (c != K_SPECIAL || p[1] == KS_SPECIAL))
721 n = MB_BYTE2LEN_CHECK(c);
722 else
723 n = 1;
724 for (i = 0; ; ++i)
725#endif
726 {
727 if (c == K_SPECIAL) /* special key or escaped K_SPECIAL */
728 {
729 c = TO_SPECIAL(p[1], p[2]);
730 p += 2;
731 }
732#ifdef FEAT_GUI
733 if (c == CSI) /* escaped CSI */
734 p += 2;
735#endif
736 if (*++p == NUL && bp->b_next != NULL)
737 {
738 bp = bp->b_next;
739 p = bp->b_str;
740 }
741#ifdef FEAT_MBYTE
742 buf[i] = c;
743 if (i == n - 1) /* last byte of a character */
744 {
745 if (n != 1)
746 c = (*mb_ptr2char)(buf);
747 break;
748 }
749 c = *p;
750 if (c == NUL) /* cannot happen? */
751 break;
752#endif
753 }
754 }
755
756 return c;
757}
758
759/*
760 * Copy the rest of the redo buffer into the stuff buffer (in a slow way).
761 * If old_redo is TRUE, use old_redobuff instead of redobuff.
762 * The escaped K_SPECIAL and CSI are copied without translation.
763 */
764 static void
765copy_redo(old_redo)
766 int old_redo;
767{
768 int c;
769
770 while ((c = read_redo(FALSE, old_redo)) != NUL)
771 stuffcharReadbuff(c);
772}
773
774/*
775 * Stuff the redo buffer into the stuffbuff.
776 * Insert the redo count into the command.
777 * If "old_redo" is TRUE, the last but one command is repeated
778 * instead of the last command (inserting text). This is used for
779 * CTRL-O <.> in insert mode
780 *
781 * return FAIL for failure, OK otherwise
782 */
783 int
784start_redo(count, old_redo)
785 long count;
786 int old_redo;
787{
788 int c;
789
790 /* init the pointers; return if nothing to redo */
791 if (read_redo(TRUE, old_redo) == FAIL)
792 return FAIL;
793
794 c = read_redo(FALSE, old_redo);
795
796 /* copy the buffer name, if present */
797 if (c == '"')
798 {
799 add_buff(&stuffbuff, (char_u *)"\"", 1L);
800 c = read_redo(FALSE, old_redo);
801
802 /* if a numbered buffer is used, increment the number */
803 if (c >= '1' && c < '9')
804 ++c;
805 add_char_buff(&stuffbuff, c);
806 c = read_redo(FALSE, old_redo);
807 }
808
809#ifdef FEAT_VISUAL
810 if (c == 'v') /* redo Visual */
811 {
812 VIsual = curwin->w_cursor;
813 VIsual_active = TRUE;
814 VIsual_select = FALSE;
815 VIsual_reselect = TRUE;
816 redo_VIsual_busy = TRUE;
817 c = read_redo(FALSE, old_redo);
818 }
819#endif
820
821 /* try to enter the count (in place of a previous count) */
822 if (count)
823 {
824 while (VIM_ISDIGIT(c)) /* skip "old" count */
825 c = read_redo(FALSE, old_redo);
826 add_num_buff(&stuffbuff, count);
827 }
828
829 /* copy from the redo buffer into the stuff buffer */
830 add_char_buff(&stuffbuff, c);
831 copy_redo(old_redo);
832 return OK;
833}
834
835/*
836 * Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
837 * the redo buffer into the stuffbuff.
838 * return FAIL for failure, OK otherwise
839 */
840 int
841start_redo_ins()
842{
843 int c;
844
845 if (read_redo(TRUE, FALSE) == FAIL)
846 return FAIL;
847 start_stuff();
848
849 /* skip the count and the command character */
850 while ((c = read_redo(FALSE, FALSE)) != NUL)
851 {
852 if (vim_strchr((char_u *)"AaIiRrOo", c) != NULL)
853 {
854 if (c == 'O' || c == 'o')
855 stuffReadbuff(NL_STR);
856 break;
857 }
858 }
859
860 /* copy the typed text from the redo buffer into the stuff buffer */
861 copy_redo(FALSE);
862 block_redo = TRUE;
863 return OK;
864}
865
866 void
867stop_redo_ins()
868{
869 block_redo = FALSE;
870}
871
872/*
873 * Initialize typebuf.tb_buf to point to typebuf_init.
874 * alloc() cannot be used here: In out-of-memory situations it would
875 * be impossible to type anything.
876 */
877 static void
878init_typebuf()
879{
880 if (typebuf.tb_buf == NULL)
881 {
882 typebuf.tb_buf = typebuf_init;
883 typebuf.tb_noremap = noremapbuf_init;
884 typebuf.tb_buflen = TYPELEN_INIT;
885 typebuf.tb_len = 0;
886 typebuf.tb_off = 0;
887 typebuf.tb_change_cnt = 1;
888 }
889}
890
891/*
892 * insert a string in position 'offset' in the typeahead buffer (for "@r"
893 * and ":normal" command, vgetorpeek() and check_termcode())
894 *
895 * If noremap is REMAP_YES, new string can be mapped again.
896 * If noremap is REMAP_NONE, new string cannot be mapped again.
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000897 * If noremap is REMAP_SKIP, fist char of new string cannot be mapped again,
898 * but abbreviations are allowed.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899 * If noremap is REMAP_SCRIPT, new string cannot be mapped again, except for
900 * script-local mappings.
901 * If noremap is > 0, that many characters of the new string cannot be mapped.
902 *
903 * If nottyped is TRUE, the string does not return KeyTyped (don't use when
904 * offset is non-zero!).
905 *
906 * If silent is TRUE, cmd_silent is set when the characters are obtained.
907 *
908 * return FAIL for failure, OK otherwise
909 */
910 int
911ins_typebuf(str, noremap, offset, nottyped, silent)
912 char_u *str;
913 int noremap;
914 int offset;
915 int nottyped;
916 int silent;
917{
918 char_u *s1, *s2;
919 int newlen;
920 int addlen;
921 int i;
922 int newoff;
923 int val;
924 int nrm;
925
926 init_typebuf();
927 if (++typebuf.tb_change_cnt == 0)
928 typebuf.tb_change_cnt = 1;
929
930 addlen = (int)STRLEN(str);
931 /*
932 * Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
933 */
934 if (offset == 0 && addlen <= typebuf.tb_off)
935 {
936 typebuf.tb_off -= addlen;
937 mch_memmove(typebuf.tb_buf + typebuf.tb_off, str, (size_t)addlen);
938 }
939 /*
940 * Need to allocate new buffer.
941 * In typebuf.tb_buf there must always be room for 3 * MAXMAPLEN + 4
942 * characters. We add some extra room to avoid having to allocate too
943 * often.
944 */
945 else
946 {
947 newoff = MAXMAPLEN + 4;
948 newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4);
949 if (newlen < 0) /* string is getting too long */
950 {
951 EMSG(_(e_toocompl)); /* also calls flush_buffers */
952 setcursor();
953 return FAIL;
954 }
955 s1 = alloc(newlen);
956 if (s1 == NULL) /* out of memory */
957 return FAIL;
958 s2 = alloc(newlen);
959 if (s2 == NULL) /* out of memory */
960 {
961 vim_free(s1);
962 return FAIL;
963 }
964 typebuf.tb_buflen = newlen;
965
966 /* copy the old chars, before the insertion point */
967 mch_memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off,
968 (size_t)offset);
969 /* copy the new chars */
970 mch_memmove(s1 + newoff + offset, str, (size_t)addlen);
971 /* copy the old chars, after the insertion point, including the NUL at
972 * the end */
973 mch_memmove(s1 + newoff + offset + addlen,
974 typebuf.tb_buf + typebuf.tb_off + offset,
975 (size_t)(typebuf.tb_len - offset + 1));
976 if (typebuf.tb_buf != typebuf_init)
977 vim_free(typebuf.tb_buf);
978 typebuf.tb_buf = s1;
979
980 mch_memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
981 (size_t)offset);
982 mch_memmove(s2 + newoff + offset + addlen,
983 typebuf.tb_noremap + typebuf.tb_off + offset,
984 (size_t)(typebuf.tb_len - offset));
985 if (typebuf.tb_noremap != noremapbuf_init)
986 vim_free(typebuf.tb_noremap);
987 typebuf.tb_noremap = s2;
988
989 typebuf.tb_off = newoff;
990 }
991 typebuf.tb_len += addlen;
992
993 /* If noremap == REMAP_SCRIPT: do remap script-local mappings. */
994 if (noremap == REMAP_SCRIPT)
995 val = RM_SCRIPT;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000996 else if (noremap == REMAP_SKIP)
997 val = RM_ABBR;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000998 else
999 val = RM_NONE;
1000
1001 /*
1002 * Adjust typebuf.tb_noremap[] for the new characters:
1003 * If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are
1004 * (sometimes) not remappable
1005 * If noremap == REMAP_YES: all the new characters are mappable
1006 * If noremap > 0: "noremap" characters are not remappable, the rest
1007 * mappable
1008 */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00001009 if (noremap == REMAP_SKIP)
1010 nrm = 1;
1011 else if (noremap < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 nrm = addlen;
1013 else
1014 nrm = noremap;
1015 for (i = 0; i < addlen; ++i)
1016 typebuf.tb_noremap[typebuf.tb_off + i + offset] =
1017 (--nrm >= 0) ? val : RM_YES;
1018
1019 /* tb_maplen and tb_silent only remember the length of mapped and/or
1020 * silent mappings at the start of the buffer, assuming that a mapped
1021 * sequence doesn't result in typed characters. */
1022 if (nottyped || typebuf.tb_maplen > offset)
1023 typebuf.tb_maplen += addlen;
1024 if (silent || typebuf.tb_silent > offset)
1025 {
1026 typebuf.tb_silent += addlen;
1027 cmd_silent = TRUE;
1028 }
1029 if (typebuf.tb_no_abbr_cnt && offset == 0) /* and not used for abbrev.s */
1030 typebuf.tb_no_abbr_cnt += addlen;
1031
1032 return OK;
1033}
1034
1035/*
1036 * Return TRUE if the typeahead buffer was changed (while waiting for a
1037 * character to arrive). Happens when a message was received from a client.
1038 * But check in a more generic way to avoid trouble: When "typebuf.tb_buf"
1039 * changed it was reallocated and the old pointer can no longer be used.
1040 * Or "typebuf.tb_off" may have been changed and we would overwrite characters
1041 * that was just added.
1042 */
1043 int
1044typebuf_changed(tb_change_cnt)
1045 int tb_change_cnt; /* old value of typebuf.tb_change_cnt */
1046{
1047 return (tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt
1048#ifdef FEAT_CLIENTSERVER
1049 || received_from_client
1050#endif
1051 ));
1052}
1053
1054/*
1055 * Return TRUE if there are no characters in the typeahead buffer that have
1056 * not been typed (result from a mapping or come from ":normal").
1057 */
1058 int
1059typebuf_typed()
1060{
1061 return typebuf.tb_maplen == 0;
1062}
1063
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001064#if defined(FEAT_VISUAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065/*
1066 * Return the number of characters that are mapped (or not typed).
1067 */
1068 int
1069typebuf_maplen()
1070{
1071 return typebuf.tb_maplen;
1072}
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001073#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074
1075/*
1076 * remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset]
1077 */
1078 void
1079del_typebuf(len, offset)
1080 int len;
1081 int offset;
1082{
1083 int i;
1084
1085 if (len == 0)
1086 return; /* nothing to do */
1087
1088 typebuf.tb_len -= len;
1089
1090 /*
1091 * Easy case: Just increase typebuf.tb_off.
1092 */
1093 if (offset == 0 && typebuf.tb_buflen - (typebuf.tb_off + len)
1094 >= 3 * MAXMAPLEN + 3)
1095 typebuf.tb_off += len;
1096 /*
1097 * Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[]
1098 */
1099 else
1100 {
1101 i = typebuf.tb_off + offset;
1102 /*
1103 * Leave some extra room at the end to avoid reallocation.
1104 */
1105 if (typebuf.tb_off > MAXMAPLEN)
1106 {
1107 mch_memmove(typebuf.tb_buf + MAXMAPLEN,
1108 typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
1109 mch_memmove(typebuf.tb_noremap + MAXMAPLEN,
1110 typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
1111 typebuf.tb_off = MAXMAPLEN;
1112 }
1113 /* adjust typebuf.tb_buf (include the NUL at the end) */
1114 mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset,
1115 typebuf.tb_buf + i + len,
1116 (size_t)(typebuf.tb_len - offset + 1));
1117 /* adjust typebuf.tb_noremap[] */
1118 mch_memmove(typebuf.tb_noremap + typebuf.tb_off + offset,
1119 typebuf.tb_noremap + i + len,
1120 (size_t)(typebuf.tb_len - offset));
1121 }
1122
1123 if (typebuf.tb_maplen > offset) /* adjust tb_maplen */
1124 {
1125 if (typebuf.tb_maplen < offset + len)
1126 typebuf.tb_maplen = offset;
1127 else
1128 typebuf.tb_maplen -= len;
1129 }
1130 if (typebuf.tb_silent > offset) /* adjust tb_silent */
1131 {
1132 if (typebuf.tb_silent < offset + len)
1133 typebuf.tb_silent = offset;
1134 else
1135 typebuf.tb_silent -= len;
1136 }
1137 if (typebuf.tb_no_abbr_cnt > offset) /* adjust tb_no_abbr_cnt */
1138 {
1139 if (typebuf.tb_no_abbr_cnt < offset + len)
1140 typebuf.tb_no_abbr_cnt = offset;
1141 else
1142 typebuf.tb_no_abbr_cnt -= len;
1143 }
1144
1145#ifdef FEAT_CLIENTSERVER
1146 /* Reset the flag that text received from a client was inserted in the
1147 * typeahead buffer. */
1148 received_from_client = FALSE;
1149#endif
1150 if (++typebuf.tb_change_cnt == 0)
1151 typebuf.tb_change_cnt = 1;
1152}
1153
1154/*
1155 * Write typed characters to script file.
1156 * If recording is on put the character in the recordbuffer.
1157 */
1158 static void
1159gotchars(s, len)
1160 char_u *s;
1161 int len;
1162{
1163 int c;
1164 char_u buf[2];
1165
1166 /* remember how many chars were last recorded */
1167 if (Recording)
1168 last_recorded_len += len;
1169
1170 buf[1] = NUL;
1171 while (len--)
1172 {
1173 /* Handle one byte at a time; no translation to be done. */
1174 c = *s++;
1175 updatescript(c);
1176
1177 if (Recording)
1178 {
1179 buf[0] = c;
1180 add_buff(&recordbuff, buf, 1L);
1181 }
1182 }
1183 may_sync_undo();
1184
1185#ifdef FEAT_EVAL
1186 /* output "debug mode" message next time in debug mode */
1187 debug_did_msg = FALSE;
1188#endif
1189
1190 /* Since characters have been typed, consider the following to be in
1191 * another mapping. Search string will be kept in history. */
1192 ++maptick;
1193}
1194
1195/*
1196 * Sync undo. Called when typed characters are obtained from the typeahead
1197 * buffer, or when a menu is used.
1198 * Do not sync:
1199 * - In Insert mode, unless cursor key has been used.
1200 * - While reading a script file.
1201 * - When no_u_sync is non-zero.
1202 */
1203 static void
1204may_sync_undo()
1205{
1206 if ((!(State & (INSERT + CMDLINE)) || arrow_used)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00001207 && scriptin[curscript] == NULL)
1208 u_sync(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209}
1210
1211/*
1212 * Make "typebuf" empty and allocate new buffers.
1213 * Returns FAIL when out of memory.
1214 */
1215 int
1216alloc_typebuf()
1217{
1218 typebuf.tb_buf = alloc(TYPELEN_INIT);
1219 typebuf.tb_noremap = alloc(TYPELEN_INIT);
1220 if (typebuf.tb_buf == NULL || typebuf.tb_noremap == NULL)
1221 {
1222 free_typebuf();
1223 return FAIL;
1224 }
1225 typebuf.tb_buflen = TYPELEN_INIT;
1226 typebuf.tb_off = 0;
1227 typebuf.tb_len = 0;
1228 typebuf.tb_maplen = 0;
1229 typebuf.tb_silent = 0;
1230 typebuf.tb_no_abbr_cnt = 0;
1231 if (++typebuf.tb_change_cnt == 0)
1232 typebuf.tb_change_cnt = 1;
1233 return OK;
1234}
1235
1236/*
1237 * Free the buffers of "typebuf".
1238 */
1239 void
1240free_typebuf()
1241{
1242 vim_free(typebuf.tb_buf);
1243 vim_free(typebuf.tb_noremap);
1244}
1245
1246/*
1247 * When doing ":so! file", the current typeahead needs to be saved, and
1248 * restored when "file" has been read completely.
1249 */
1250static typebuf_T saved_typebuf[NSCRIPT];
1251
1252 int
1253save_typebuf()
1254{
1255 init_typebuf();
1256 saved_typebuf[curscript] = typebuf;
1257 /* If out of memory: restore typebuf and close file. */
1258 if (alloc_typebuf() == FAIL)
1259 {
1260 closescript();
1261 return FAIL;
1262 }
1263 return OK;
1264}
1265
1266#if defined(FEAT_EVAL) || defined(FEAT_EX_EXTRA) || defined(PROTO)
1267
1268/*
1269 * Save all three kinds of typeahead, so that the user must type at a prompt.
1270 */
1271 void
1272save_typeahead(tp)
1273 tasave_T *tp;
1274{
1275 tp->save_typebuf = typebuf;
1276 tp->typebuf_valid = (alloc_typebuf() == OK);
1277 if (!tp->typebuf_valid)
1278 typebuf = tp->save_typebuf;
1279
1280 tp->save_stuffbuff = stuffbuff;
1281 stuffbuff.bh_first.b_next = NULL;
1282# ifdef USE_INPUT_BUF
1283 tp->save_inputbuf = get_input_buf();
1284# endif
1285}
1286
1287/*
1288 * Restore the typeahead to what it was before calling save_typeahead().
1289 * The allocated memory is freed, can only be called once!
1290 */
1291 void
1292restore_typeahead(tp)
1293 tasave_T *tp;
1294{
1295 if (tp->typebuf_valid)
1296 {
1297 free_typebuf();
1298 typebuf = tp->save_typebuf;
1299 }
1300
1301 free_buff(&stuffbuff);
1302 stuffbuff = tp->save_stuffbuff;
1303# ifdef USE_INPUT_BUF
1304 set_input_buf(tp->save_inputbuf);
1305# endif
1306}
1307#endif
1308
1309/*
1310 * Open a new script file for the ":source!" command.
1311 */
1312 void
1313openscript(name, directly)
1314 char_u *name;
1315 int directly; /* when TRUE execute directly */
1316{
1317 if (curscript + 1 == NSCRIPT)
1318 {
1319 EMSG(_(e_nesting));
1320 return;
1321 }
1322
1323 if (scriptin[curscript] != NULL) /* already reading script */
1324 ++curscript;
1325 /* use NameBuff for expanded name */
1326 expand_env(name, NameBuff, MAXPATHL);
1327 if ((scriptin[curscript] = mch_fopen((char *)NameBuff, READBIN)) == NULL)
1328 {
1329 EMSG2(_(e_notopen), name);
1330 if (curscript)
1331 --curscript;
1332 return;
1333 }
1334 if (save_typebuf() == FAIL)
1335 return;
1336
1337 /*
1338 * Execute the commands from the file right now when using ":source!"
1339 * after ":global" or ":argdo" or in a loop. Also when another command
1340 * follows. This means the display won't be updated. Don't do this
1341 * always, "make test" would fail.
1342 */
1343 if (directly)
1344 {
1345 oparg_T oa;
1346 int oldcurscript;
1347 int save_State = State;
1348 int save_restart_edit = restart_edit;
1349 int save_insertmode = p_im;
1350 int save_finish_op = finish_op;
1351 int save_msg_scroll = msg_scroll;
1352
1353 State = NORMAL;
1354 msg_scroll = FALSE; /* no msg scrolling in Normal mode */
1355 restart_edit = 0; /* don't go to Insert mode */
1356 p_im = FALSE; /* don't use 'insertmode' */
1357 clear_oparg(&oa);
1358 finish_op = FALSE;
1359
1360 oldcurscript = curscript;
1361 do
1362 {
1363 update_topline_cursor(); /* update cursor position and topline */
1364 normal_cmd(&oa, FALSE); /* execute one command */
1365 vpeekc(); /* check for end of file */
1366 }
1367 while (scriptin[oldcurscript] != NULL);
1368
1369 State = save_State;
1370 msg_scroll = save_msg_scroll;
1371 restart_edit = save_restart_edit;
1372 p_im = save_insertmode;
1373 finish_op = save_finish_op;
1374 }
1375}
1376
1377/*
1378 * Close the currently active input script.
1379 */
1380 static void
1381closescript()
1382{
1383 free_typebuf();
1384 typebuf = saved_typebuf[curscript];
1385
1386 fclose(scriptin[curscript]);
1387 scriptin[curscript] = NULL;
1388 if (curscript > 0)
1389 --curscript;
1390}
1391
Bram Moolenaarea408852005-06-25 22:49:46 +00001392#if defined(EXITFREE) || defined(PROTO)
1393 void
1394close_all_scripts()
1395{
1396 while (scriptin[0] != NULL)
1397 closescript();
1398}
1399#endif
1400
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1402/*
1403 * Return TRUE when reading keys from a script file.
1404 */
1405 int
1406using_script()
1407{
1408 return scriptin[curscript] != NULL;
1409}
1410#endif
1411
1412/*
Bram Moolenaar238f4fa2005-06-27 22:25:50 +00001413 * This function is called just before doing a blocking wait. Thus after
1414 * waiting 'updatetime' for a character to arrive.
1415 */
1416 void
1417before_blocking()
1418{
1419 updatescript(0);
1420#ifdef FEAT_EVAL
1421 garbage_collect();
1422#endif
1423}
1424
1425/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426 * updatescipt() is called when a character can be written into the script file
1427 * or when we have waited some time for a character (c == 0)
1428 *
1429 * All the changed memfiles are synced if c == 0 or when the number of typed
1430 * characters reaches 'updatecount' and 'updatecount' is non-zero.
1431 */
1432 void
1433updatescript(c)
1434 int c;
1435{
1436 static int count = 0;
1437
1438 if (c && scriptout)
1439 putc(c, scriptout);
1440 if (c == 0 || (p_uc > 0 && ++count >= p_uc))
1441 {
1442 ml_sync_all(c == 0, TRUE);
1443 count = 0;
1444 }
1445}
1446
1447#define KL_PART_KEY -1 /* keylen value for incomplete key-code */
1448#define KL_PART_MAP -2 /* keylen value for incomplete mapping */
1449
1450static int old_char = -1; /* character put back by vungetc() */
1451static int old_mod_mask; /* mod_mask for ungotten character */
1452
1453/*
1454 * Get the next input character.
1455 * Can return a special key or a multi-byte character.
1456 * Can return NUL when called recursively, use safe_vgetc() if that's not
1457 * wanted.
1458 * This translates escaped K_SPECIAL and CSI bytes to a K_SPECIAL or CSI byte.
1459 * Collects the bytes of a multibyte character into the whole character.
1460 * Returns the modifers in the global "mod_mask".
1461 */
1462 int
1463vgetc()
1464{
1465 int c, c2;
1466#ifdef FEAT_MBYTE
1467 int n;
1468 char_u buf[MB_MAXBYTES];
1469 int i;
1470#endif
1471
1472 /*
1473 * If a character was put back with vungetc, it was already processed.
1474 * Return it directly.
1475 */
1476 if (old_char != -1)
1477 {
1478 c = old_char;
1479 old_char = -1;
1480 mod_mask = old_mod_mask;
1481 return c;
1482 }
1483
1484 mod_mask = 0x0;
1485 last_recorded_len = 0;
1486 for (;;) /* this is done twice if there are modifiers */
1487 {
1488 if (mod_mask) /* no mapping after modifier has been read */
1489 {
1490 ++no_mapping;
1491 ++allow_keys;
1492 }
1493 c = vgetorpeek(TRUE);
1494 if (mod_mask)
1495 {
1496 --no_mapping;
1497 --allow_keys;
1498 }
1499
1500 /* Get two extra bytes for special keys */
1501 if (c == K_SPECIAL
1502#ifdef FEAT_GUI
1503 || c == CSI
1504#endif
1505 )
1506 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001507 int save_allow_keys = allow_keys;
1508
Bram Moolenaar071d4272004-06-13 20:20:40 +00001509 ++no_mapping;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001510 allow_keys = 0; /* make sure BS is not found */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 c2 = vgetorpeek(TRUE); /* no mapping for these chars */
1512 c = vgetorpeek(TRUE);
1513 --no_mapping;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001514 allow_keys = save_allow_keys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515 if (c2 == KS_MODIFIER)
1516 {
1517 mod_mask = c;
1518 continue;
1519 }
1520 c = TO_SPECIAL(c2, c);
1521
1522#if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
1523 /* Handle K_TEAROFF here, the caller of vgetc() doesn't need to
1524 * know that a menu was torn off */
1525 if (c == K_TEAROFF)
1526 {
1527 char_u name[200];
1528 int i;
1529
1530 /* get menu path, it ends with a <CR> */
1531 for (i = 0; (c = vgetorpeek(TRUE)) != '\r'; )
1532 {
1533 name[i] = c;
1534 if (i < 199)
1535 ++i;
1536 }
1537 name[i] = NUL;
1538 gui_make_tearoff(name);
1539 continue;
1540 }
1541#endif
Bram Moolenaarcf0c5542006-02-09 23:48:02 +00001542#if defined(FEAT_GUI) && defined(HAVE_GTK2) && defined(FEAT_MENU)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001543 /* GTK: <F10> normally selects the menu, but it's passed until
1544 * here to allow mapping it. Intercept and invoke the GTK
1545 * behavior if it's not mapped. */
1546 if (c == K_F10 && gui.menubar != NULL)
1547 {
1548 gtk_menu_shell_select_first(GTK_MENU_SHELL(gui.menubar), FALSE);
1549 continue;
1550 }
1551#endif
1552
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553#ifdef FEAT_GUI
1554 /* Translate K_CSI to CSI. The special key is only used to avoid
1555 * it being recognized as the start of a special key. */
1556 if (c == K_CSI)
1557 c = CSI;
1558#endif
1559 }
1560#ifdef MSDOS
1561 /*
1562 * If K_NUL was typed, it is replaced by K_NUL, 3 in mch_inchar().
1563 * Delete the 3 here.
1564 */
1565 else if (c == K_NUL && vpeekc() == 3)
1566 (void)vgetorpeek(TRUE);
1567#endif
1568
Bram Moolenaara88d9682005-03-25 21:45:43 +00001569 /* a keypad or special function key was not mapped, use it like
1570 * its ASCII equivalent */
1571 switch (c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572 {
Bram Moolenaara88d9682005-03-25 21:45:43 +00001573 case K_KPLUS: c = '+'; break;
1574 case K_KMINUS: c = '-'; break;
1575 case K_KDIVIDE: c = '/'; break;
1576 case K_KMULTIPLY: c = '*'; break;
1577 case K_KENTER: c = CAR; break;
1578 case K_KPOINT:
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001579#ifdef WIN32
Bram Moolenaara88d9682005-03-25 21:45:43 +00001580 /* Can be either '.' or a ',', *
1581 * depending on the type of keypad. */
1582 c = MapVirtualKey(VK_DECIMAL, 2); break;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001583#else
Bram Moolenaara88d9682005-03-25 21:45:43 +00001584 c = '.'; break;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001585#endif
Bram Moolenaara88d9682005-03-25 21:45:43 +00001586 case K_K0: c = '0'; break;
1587 case K_K1: c = '1'; break;
1588 case K_K2: c = '2'; break;
1589 case K_K3: c = '3'; break;
1590 case K_K4: c = '4'; break;
1591 case K_K5: c = '5'; break;
1592 case K_K6: c = '6'; break;
1593 case K_K7: c = '7'; break;
1594 case K_K8: c = '8'; break;
1595 case K_K9: c = '9'; break;
1596
1597 case K_XHOME:
1598 case K_ZHOME: if (mod_mask == MOD_MASK_SHIFT)
1599 {
1600 c = K_S_HOME;
1601 mod_mask = 0;
1602 }
1603 else if (mod_mask == MOD_MASK_CTRL)
1604 {
1605 c = K_C_HOME;
1606 mod_mask = 0;
1607 }
1608 else
1609 c = K_HOME;
1610 break;
1611 case K_XEND:
1612 case K_ZEND: if (mod_mask == MOD_MASK_SHIFT)
1613 {
1614 c = K_S_END;
1615 mod_mask = 0;
1616 }
1617 else if (mod_mask == MOD_MASK_CTRL)
1618 {
1619 c = K_C_END;
1620 mod_mask = 0;
1621 }
1622 else
1623 c = K_END;
1624 break;
1625
1626 case K_XUP: c = K_UP; break;
1627 case K_XDOWN: c = K_DOWN; break;
1628 case K_XLEFT: c = K_LEFT; break;
1629 case K_XRIGHT: c = K_RIGHT; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 }
1631
1632#ifdef FEAT_MBYTE
1633 /* For a multi-byte character get all the bytes and return the
1634 * converted character.
1635 * Note: This will loop until enough bytes are received!
1636 */
1637 if (has_mbyte && (n = MB_BYTE2LEN_CHECK(c)) > 1)
1638 {
1639 ++no_mapping;
1640 buf[0] = c;
1641 for (i = 1; i < n; ++i)
1642 {
1643 buf[i] = vgetorpeek(TRUE);
1644 if (buf[i] == K_SPECIAL
1645#ifdef FEAT_GUI
1646 || buf[i] == CSI
1647#endif
1648 )
1649 {
1650 /* Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
1651 * which represents a K_SPECIAL (0x80),
1652 * or a CSI - KS_EXTRA - KE_CSI sequence, which represents
1653 * a CSI (0x9B),
1654 * of a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI too. */
1655 c = vgetorpeek(TRUE);
1656 if (vgetorpeek(TRUE) == (int)KE_CSI && c == KS_EXTRA)
1657 buf[i] = CSI;
1658 }
1659 }
1660 --no_mapping;
1661 c = (*mb_ptr2char)(buf);
1662 }
1663#endif
1664
1665 return c;
1666 }
1667}
1668
1669/*
1670 * Like vgetc(), but never return a NUL when called recursively, get a key
1671 * directly from the user (ignoring typeahead).
1672 */
1673 int
1674safe_vgetc()
1675{
1676 int c;
1677
1678 c = vgetc();
1679 if (c == NUL)
1680 c = get_keystroke();
1681 return c;
1682}
1683
1684/*
1685 * Check if a character is available, such that vgetc() will not block.
1686 * If the next character is a special character or multi-byte, the returned
1687 * character is not valid!.
1688 */
1689 int
1690vpeekc()
1691{
1692 if (old_char != -1)
1693 return old_char;
1694 return vgetorpeek(FALSE);
1695}
1696
1697#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
1698/*
1699 * Like vpeekc(), but don't allow mapping. Do allow checking for terminal
1700 * codes.
1701 */
1702 int
1703vpeekc_nomap()
1704{
1705 int c;
1706
1707 ++no_mapping;
1708 ++allow_keys;
1709 c = vpeekc();
1710 --no_mapping;
1711 --allow_keys;
1712 return c;
1713}
1714#endif
1715
1716#if defined(FEAT_INS_EXPAND) || defined(PROTO)
1717/*
1718 * Check if any character is available, also half an escape sequence.
1719 * Trick: when no typeahead found, but there is something in the typeahead
1720 * buffer, it must be an ESC that is recognized as the start of a key code.
1721 */
1722 int
1723vpeekc_any()
1724{
1725 int c;
1726
1727 c = vpeekc();
1728 if (c == NUL && typebuf.tb_len > 0)
1729 c = ESC;
1730 return c;
1731}
1732#endif
1733
1734/*
1735 * Call vpeekc() without causing anything to be mapped.
1736 * Return TRUE if a character is available, FALSE otherwise.
1737 */
1738 int
1739char_avail()
1740{
1741 int retval;
1742
1743 ++no_mapping;
1744 retval = vpeekc();
1745 --no_mapping;
1746 return (retval != NUL);
1747}
1748
1749 void
1750vungetc(c) /* unget one character (can only be done once!) */
1751 int c;
1752{
1753 old_char = c;
1754 old_mod_mask = mod_mask;
1755}
1756
1757/*
1758 * get a character:
1759 * 1. from the stuffbuffer
1760 * This is used for abbreviated commands like "D" -> "d$".
1761 * Also used to redo a command for ".".
1762 * 2. from the typeahead buffer
1763 * Stores text obtained previously but not used yet.
1764 * Also stores the result of mappings.
1765 * Also used for the ":normal" command.
1766 * 3. from the user
1767 * This may do a blocking wait if "advance" is TRUE.
1768 *
1769 * if "advance" is TRUE (vgetc()):
1770 * really get the character.
1771 * KeyTyped is set to TRUE in the case the user typed the key.
1772 * KeyStuffed is TRUE if the character comes from the stuff buffer.
1773 * if "advance" is FALSE (vpeekc()):
1774 * just look whether there is a character available.
1775 *
1776 * When "no_mapping" is zero, checks for mappings in the current mode.
1777 * Only returns one byte (of a multi-byte character).
1778 * K_SPECIAL and CSI may be escaped, need to get two more bytes then.
1779 */
1780 static int
1781vgetorpeek(advance)
1782 int advance;
1783{
1784 int c, c1;
1785 int keylen;
1786 char_u *s;
1787 mapblock_T *mp;
1788#ifdef FEAT_LOCALMAP
1789 mapblock_T *mp2;
1790#endif
1791 mapblock_T *mp_match;
1792 int mp_match_len = 0;
1793 int timedout = FALSE; /* waited for more than 1 second
1794 for mapping to complete */
1795 int mapdepth = 0; /* check for recursive mapping */
1796 int mode_deleted = FALSE; /* set when mode has been deleted */
1797 int local_State;
1798 int mlen;
1799 int max_mlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 int i;
Bram Moolenaar4e427192006-03-10 21:34:27 +00001801#ifdef FEAT_CMDL_INFO
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 int new_wcol, new_wrow;
1803#endif
1804#ifdef FEAT_GUI
1805# ifdef FEAT_MENU
1806 int idx;
1807# endif
1808 int shape_changed = FALSE; /* adjusted cursor shape */
1809#endif
1810 int n;
1811#ifdef FEAT_LANGMAP
1812 int nolmaplen;
1813#endif
1814 int old_wcol, old_wrow;
Bram Moolenaar28a37ff2005-03-15 22:28:00 +00001815 int wait_tb_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816
1817 /*
1818 * This function doesn't work very well when called recursively. This may
1819 * happen though, because of:
1820 * 1. The call to add_to_showcmd(). char_avail() is then used to check if
1821 * there is a character available, which calls this function. In that
1822 * case we must return NUL, to indicate no character is available.
1823 * 2. A GUI callback function writes to the screen, causing a
1824 * wait_return().
1825 * Using ":normal" can also do this, but it saves the typeahead buffer,
1826 * thus it should be OK. But don't get a key from the user then.
1827 */
Bram Moolenaar5555acc2006-04-07 21:33:12 +00001828 if (vgetc_busy > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829#ifdef FEAT_EX_EXTRA
1830 && ex_normal_busy == 0
1831#endif
1832 )
1833 return NUL;
1834
1835 local_State = get_real_state();
1836
Bram Moolenaar5555acc2006-04-07 21:33:12 +00001837 ++vgetc_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838
1839 if (advance)
1840 KeyStuffed = FALSE;
1841
1842 init_typebuf();
1843 start_stuff();
1844 if (advance && typebuf.tb_maplen == 0)
1845 Exec_reg = FALSE;
1846 do
1847 {
1848/*
1849 * get a character: 1. from the stuffbuffer
1850 */
1851 if (typeahead_char != 0)
1852 {
1853 c = typeahead_char;
1854 if (advance)
1855 typeahead_char = 0;
1856 }
1857 else
1858 c = read_stuff(advance);
1859 if (c != NUL && !got_int)
1860 {
1861 if (advance)
1862 {
1863 /* KeyTyped = FALSE; When the command that stuffed something
1864 * was typed, behave like the stuffed command was typed.
1865 * needed for CTRL-W CTRl-] to open a fold, for example. */
1866 KeyStuffed = TRUE;
1867 }
1868 if (typebuf.tb_no_abbr_cnt == 0)
1869 typebuf.tb_no_abbr_cnt = 1; /* no abbreviations now */
1870 }
1871 else
1872 {
1873 /*
1874 * Loop until we either find a matching mapped key, or we
1875 * are sure that it is not a mapped key.
1876 * If a mapped key sequence is found we go back to the start to
1877 * try re-mapping.
1878 */
1879 for (;;)
1880 {
1881 /*
1882 * ui_breakcheck() is slow, don't use it too often when
1883 * inside a mapping. But call it each time for typed
1884 * characters.
1885 */
1886 if (typebuf.tb_maplen)
1887 line_breakcheck();
1888 else
1889 ui_breakcheck(); /* check for CTRL-C */
1890 keylen = 0;
1891 if (got_int)
1892 {
1893 /* flush all input */
1894 c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L,
1895 typebuf.tb_change_cnt);
1896 /*
1897 * If inchar() returns TRUE (script file was active) or we
1898 * are inside a mapping, get out of insert mode.
1899 * Otherwise we behave like having gotten a CTRL-C.
1900 * As a result typing CTRL-C in insert mode will
1901 * really insert a CTRL-C.
1902 */
1903 if ((c || typebuf.tb_maplen)
1904 && (State & (INSERT + CMDLINE)))
1905 c = ESC;
1906 else
1907 c = Ctrl_C;
1908 flush_buffers(TRUE); /* flush all typeahead */
1909
1910 /* Also record this character, it might be needed to
1911 * get out of Insert mode. */
1912 *typebuf.tb_buf = c;
1913 gotchars(typebuf.tb_buf, 1);
1914 cmd_silent = FALSE;
1915
1916 break;
1917 }
1918 else if (typebuf.tb_len > 0)
1919 {
1920 /*
1921 * Check for a mappable key sequence.
1922 * Walk through one maphash[] list until we find an
1923 * entry that matches.
1924 *
1925 * Don't look for mappings if:
1926 * - no_mapping set: mapping disabled (e.g. for CTRL-V)
1927 * - maphash_valid not set: no mappings present.
1928 * - typebuf.tb_buf[typebuf.tb_off] should not be remapped
1929 * - in insert or cmdline mode and 'paste' option set
1930 * - waiting for "hit return to continue" and CR or SPACE
1931 * typed
1932 * - waiting for a char with --more--
1933 * - in Ctrl-X mode, and we get a valid char for that mode
1934 */
1935 mp = NULL;
1936 max_mlen = 0;
1937 c1 = typebuf.tb_buf[typebuf.tb_off];
1938 if (no_mapping == 0 && maphash_valid
1939 && (no_zero_mapping == 0 || c1 != '0')
1940 && (typebuf.tb_maplen == 0
1941 || (p_remap
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00001942 && (typebuf.tb_noremap[typebuf.tb_off]
1943 & (RM_NONE|RM_ABBR)) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 && !(p_paste && (State & (INSERT + CMDLINE)))
1945 && !(State == HITRETURN && (c1 == CAR || c1 == ' '))
1946 && State != ASKMORE
1947 && State != CONFIRM
1948#ifdef FEAT_INS_EXPAND
1949 && !((ctrl_x_mode != 0 && vim_is_ctrl_x_key(c1))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001950 || ((compl_cont_status & CONT_LOCAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 && (c1 == Ctrl_N || c1 == Ctrl_P)))
1952#endif
1953 )
1954 {
1955#ifdef FEAT_LANGMAP
1956 if (c1 == K_SPECIAL)
1957 nolmaplen = 2;
1958 else
1959 {
1960 LANGMAP_ADJUST(c1, TRUE);
1961 nolmaplen = 0;
1962 }
1963#endif
1964#ifdef FEAT_LOCALMAP
1965 /* First try buffer-local mappings. */
1966 mp = curbuf->b_maphash[MAP_HASH(local_State, c1)];
1967 mp2 = maphash[MAP_HASH(local_State, c1)];
1968 if (mp == NULL)
1969 {
1970 mp = mp2;
1971 mp2 = NULL;
1972 }
1973#else
1974 mp = maphash[MAP_HASH(local_State, c1)];
1975#endif
1976 /*
1977 * Loop until a partly matching mapping is found or
1978 * all (local) mappings have been checked.
1979 * The longest full match is remembered in "mp_match".
1980 * A full match is only accepted if there is no partly
1981 * match, so "aa" and "aaa" can both be mapped.
1982 */
1983 mp_match = NULL;
1984 mp_match_len = 0;
1985 for ( ; mp != NULL;
1986#ifdef FEAT_LOCALMAP
1987 mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
1988#endif
1989 (mp = mp->m_next))
1990 {
1991 /*
1992 * Only consider an entry if the first character
1993 * matches and it is for the current state.
1994 * Skip ":lmap" mappings if keys were mapped.
1995 */
1996 if (mp->m_keys[0] == c1
1997 && (mp->m_mode & local_State)
1998 && ((mp->m_mode & LANGMAP) == 0
1999 || typebuf.tb_maplen == 0))
2000 {
2001#ifdef FEAT_LANGMAP
2002 int nomap = nolmaplen;
2003 int c2;
2004#endif
2005 /* find the match length of this mapping */
2006 for (mlen = 1; mlen < typebuf.tb_len; ++mlen)
2007 {
2008#ifdef FEAT_LANGMAP
2009 c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
2010 if (nomap > 0)
2011 --nomap;
2012 else if (c2 == K_SPECIAL)
2013 nomap = 2;
2014 else
2015 LANGMAP_ADJUST(c2, TRUE);
2016 if (mp->m_keys[mlen] != c2)
2017#else
2018 if (mp->m_keys[mlen] !=
2019 typebuf.tb_buf[typebuf.tb_off + mlen])
2020#endif
2021 break;
2022 }
2023
2024#ifdef FEAT_MBYTE
2025 /* Don't allow mapping the first byte(s) of a
2026 * multi-byte char. Happens when mapping
2027 * <M-a> and then changing 'encoding'. */
2028 if (has_mbyte && MB_BYTE2LEN(c1)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002029 > (*mb_ptr2len)(mp->m_keys))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030 mlen = 0;
2031#endif
2032 /*
2033 * Check an entry whether it matches.
2034 * - Full match: mlen == keylen
2035 * - Partly match: mlen == typebuf.tb_len
2036 */
2037 keylen = mp->m_keylen;
2038 if (mlen == keylen
2039 || (mlen == typebuf.tb_len
2040 && typebuf.tb_len < keylen))
2041 {
2042 /*
2043 * If only script-local mappings are
2044 * allowed, check if the mapping starts
2045 * with K_SNR.
2046 */
2047 s = typebuf.tb_noremap + typebuf.tb_off;
2048 if (*s == RM_SCRIPT
2049 && (mp->m_keys[0] != K_SPECIAL
2050 || mp->m_keys[1] != KS_EXTRA
2051 || mp->m_keys[2]
2052 != (int)KE_SNR))
2053 continue;
2054 /*
2055 * If one of the typed keys cannot be
2056 * remapped, skip the entry.
2057 */
2058 for (n = mlen; --n >= 0; )
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00002059 if (*s++ & (RM_NONE|RM_ABBR))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 break;
2061 if (n >= 0)
2062 continue;
2063
2064 if (keylen > typebuf.tb_len)
2065 {
2066 if (!timedout)
2067 {
2068 /* break at a partly match */
2069 keylen = KL_PART_MAP;
2070 break;
2071 }
2072 }
2073 else if (keylen > mp_match_len)
2074 {
2075 /* found a longer match */
2076 mp_match = mp;
2077 mp_match_len = keylen;
2078 }
2079 }
2080 else
2081 /* No match; may have to check for
2082 * termcode at next character. */
2083 if (max_mlen < mlen)
2084 max_mlen = mlen;
2085 }
2086 }
2087
2088 /* If no partly match found, use the longest full
2089 * match. */
2090 if (keylen != KL_PART_MAP)
2091 {
2092 mp = mp_match;
2093 keylen = mp_match_len;
2094 }
2095 }
2096
2097 /* Check for match with 'pastetoggle' */
2098 if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL)))
2099 {
2100 for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen];
2101 ++mlen)
2102 if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off
2103 + mlen])
2104 break;
2105 if (p_pt[mlen] == NUL) /* match */
2106 {
2107 /* write chars to script file(s) */
2108 if (mlen > typebuf.tb_maplen)
2109 gotchars(typebuf.tb_buf + typebuf.tb_off
2110 + typebuf.tb_maplen,
2111 mlen - typebuf.tb_maplen);
2112
2113 del_typebuf(mlen, 0); /* remove the chars */
2114 set_option_value((char_u *)"paste",
2115 (long)!p_paste, NULL, 0);
2116 if (!(State & INSERT))
2117 {
2118 msg_col = 0;
2119 msg_row = Rows - 1;
2120 msg_clr_eos(); /* clear ruler */
2121 }
2122 showmode();
2123 setcursor();
2124 continue;
2125 }
2126 /* Need more chars for partly match. */
2127 if (mlen == typebuf.tb_len)
2128 keylen = KL_PART_MAP;
2129 else if (max_mlen < mlen)
2130 /* no match, may have to check for termcode at
2131 * next character */
2132 max_mlen = mlen + 1;
2133 }
2134
2135 if ((mp == NULL || max_mlen >= mp_match_len)
2136 && keylen != KL_PART_MAP)
2137 {
2138 /*
2139 * When no matching mapping found or found a
2140 * non-matching mapping that matches at least what the
2141 * matching mapping matched:
2142 * Check if we have a terminal code, when:
2143 * mapping is allowed,
2144 * keys have not been mapped,
2145 * and not an ESC sequence, not in insert mode or
2146 * p_ek is on,
2147 * and when not timed out,
2148 */
2149 if ((no_mapping == 0 || allow_keys != 0)
2150 && (typebuf.tb_maplen == 0
2151 || (p_remap && typebuf.tb_noremap[
2152 typebuf.tb_off] == RM_YES))
2153 && !timedout)
2154 {
2155 keylen = check_termcode(max_mlen + 1, NULL, 0);
2156
2157 /*
2158 * When getting a partial match, but the last
2159 * characters were not typed, don't wait for a
2160 * typed character to complete the termcode.
2161 * This helps a lot when a ":normal" command ends
2162 * in an ESC.
2163 */
2164 if (keylen < 0
2165 && typebuf.tb_len == typebuf.tb_maplen)
2166 keylen = 0;
2167 }
2168 else
2169 keylen = 0;
2170 if (keylen == 0) /* no matching terminal code */
2171 {
2172#ifdef AMIGA /* check for window bounds report */
2173 if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[
2174 typebuf.tb_off] & 0xff) == CSI)
2175 {
2176 for (s = typebuf.tb_buf + typebuf.tb_off + 1;
2177 s < typebuf.tb_buf + typebuf.tb_off
2178 + typebuf.tb_len
2179 && (VIM_ISDIGIT(*s) || *s == ';'
2180 || *s == ' ');
2181 ++s)
2182 ;
2183 if (*s == 'r' || *s == '|') /* found one */
2184 {
2185 del_typebuf((int)(s + 1 -
2186 (typebuf.tb_buf + typebuf.tb_off)), 0);
2187 /* get size and redraw screen */
2188 shell_resized();
2189 continue;
2190 }
2191 if (*s == NUL) /* need more characters */
2192 keylen = KL_PART_KEY;
2193 }
2194 if (keylen >= 0)
2195#endif
2196 /* When there was a matching mapping and no
2197 * termcode could be replaced after another one,
2198 * use that mapping. */
2199 if (mp == NULL)
2200 {
2201/*
2202 * get a character: 2. from the typeahead buffer
2203 */
2204 c = typebuf.tb_buf[typebuf.tb_off] & 255;
2205 if (advance) /* remove chars from tb_buf */
2206 {
2207 cmd_silent = (typebuf.tb_silent > 0);
2208 if (typebuf.tb_maplen > 0)
2209 KeyTyped = FALSE;
2210 else
2211 {
2212 KeyTyped = TRUE;
2213 /* write char to script file(s) */
2214 gotchars(typebuf.tb_buf
2215 + typebuf.tb_off, 1);
2216 }
2217 KeyNoremap = (typebuf.tb_noremap[
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00002218 typebuf.tb_off]
2219 & (RM_NONE|RM_SCRIPT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 del_typebuf(1, 0);
2221 }
2222 break; /* got character, break for loop */
2223 }
2224 }
2225 if (keylen > 0) /* full matching terminal code */
2226 {
2227#if defined(FEAT_GUI) && defined(FEAT_MENU)
2228 if (typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
2229 && typebuf.tb_buf[typebuf.tb_off + 1]
2230 == KS_MENU)
2231 {
2232 /*
2233 * Using a menu may cause a break in undo!
2234 * It's like using gotchars(), but without
2235 * recording or writing to a script file.
2236 */
2237 may_sync_undo();
2238 del_typebuf(3, 0);
2239 idx = get_menu_index(current_menu, local_State);
2240 if (idx != MENU_INDEX_INVALID)
2241 {
2242# ifdef FEAT_VISUAL
2243 /*
Bram Moolenaar371d5402006-03-20 21:47:49 +00002244 * In Select mode and a Visual mode menu
2245 * is used: Switch to Visual mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 * temporarily. Append K_SELECT to switch
2247 * back to Select mode.
2248 */
Bram Moolenaar371d5402006-03-20 21:47:49 +00002249 if (VIsual_active && VIsual_select
2250 && (current_menu->modes & VISUAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251 {
2252 VIsual_select = FALSE;
2253 (void)ins_typebuf(K_SELECT_STRING,
2254 REMAP_NONE, 0, TRUE, FALSE);
2255 }
2256# endif
2257 ins_typebuf(current_menu->strings[idx],
2258 current_menu->noremap[idx],
2259 0, TRUE,
2260 current_menu->silent[idx]);
2261 }
2262 }
2263#endif /* FEAT_GUI */
2264 continue; /* try mapping again */
2265 }
2266
2267 /* Partial match: get some more characters. When a
2268 * matching mapping was found use that one. */
2269 if (mp == NULL || keylen < 0)
2270 keylen = KL_PART_KEY;
2271 else
2272 keylen = mp_match_len;
2273 }
2274
2275 /* complete match */
2276 if (keylen >= 0 && keylen <= typebuf.tb_len)
2277 {
2278 /* write chars to script file(s) */
2279 if (keylen > typebuf.tb_maplen)
2280 gotchars(typebuf.tb_buf + typebuf.tb_off
2281 + typebuf.tb_maplen,
2282 keylen - typebuf.tb_maplen);
2283
2284 cmd_silent = (typebuf.tb_silent > 0);
2285 del_typebuf(keylen, 0); /* remove the mapped keys */
2286
2287 /*
2288 * Put the replacement string in front of mapstr.
2289 * The depth check catches ":map x y" and ":map y x".
2290 */
2291 if (++mapdepth >= p_mmd)
2292 {
2293 EMSG(_("E223: recursive mapping"));
2294 if (State & CMDLINE)
2295 redrawcmdline();
2296 else
2297 setcursor();
2298 flush_buffers(FALSE);
2299 mapdepth = 0; /* for next one */
2300 c = -1;
2301 break;
2302 }
2303
2304#ifdef FEAT_VISUAL
2305 /*
Bram Moolenaar371d5402006-03-20 21:47:49 +00002306 * In Select mode and a Visual mode mapping is used:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 * Switch to Visual mode temporarily. Append K_SELECT
2308 * to switch back to Select mode.
2309 */
Bram Moolenaar371d5402006-03-20 21:47:49 +00002310 if (VIsual_active && VIsual_select
2311 && (mp->m_mode & VISUAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 {
2313 VIsual_select = FALSE;
2314 (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE,
2315 0, TRUE, FALSE);
2316 }
2317#endif
2318
Bram Moolenaar4e427192006-03-10 21:34:27 +00002319#ifdef FEAT_EVAL
2320 /*
2321 * Handle ":map <expr>": evaluate the {rhs} as an
Bram Moolenaar5555acc2006-04-07 21:33:12 +00002322 * expression. Save and restore the typeahead so that
2323 * getchar() can be used.
Bram Moolenaar4e427192006-03-10 21:34:27 +00002324 */
2325 if (mp->m_expr)
Bram Moolenaar5555acc2006-04-07 21:33:12 +00002326 {
2327 tasave_T tabuf;
2328 int save_vgetc_busy = vgetc_busy;
2329
2330 save_typeahead(&tabuf);
2331 if (tabuf.typebuf_valid)
2332 {
2333 vgetc_busy = 0;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00002334 s = eval_map_expr(mp->m_str);
Bram Moolenaar5555acc2006-04-07 21:33:12 +00002335 vgetc_busy = save_vgetc_busy;
2336 }
2337 else
2338 s = NULL;
2339 restore_typeahead(&tabuf);
2340 }
Bram Moolenaar4e427192006-03-10 21:34:27 +00002341 else
2342#endif
2343 s = mp->m_str;
2344
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 /*
2346 * Insert the 'to' part in the typebuf.tb_buf.
2347 * If 'from' field is the same as the start of the
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00002348 * 'to' field, don't remap the first character (but do
2349 * allow abbreviations).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 * If m_noremap is set, don't remap the whole 'to'
2351 * part.
2352 */
Bram Moolenaar4e427192006-03-10 21:34:27 +00002353 if (s == NULL)
2354 i = FAIL;
2355 else
2356 {
2357 i = ins_typebuf(s,
2358 mp->m_noremap != REMAP_YES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 ? mp->m_noremap
Bram Moolenaar4e427192006-03-10 21:34:27 +00002360 : STRNCMP(s, mp->m_keys,
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00002361 (size_t)keylen) != 0
2362 ? REMAP_YES : REMAP_SKIP,
Bram Moolenaar4e427192006-03-10 21:34:27 +00002363 0, TRUE, cmd_silent || mp->m_silent);
2364#ifdef FEAT_EVAL
2365 if (mp->m_expr)
2366 vim_free(s);
2367#endif
2368 }
2369 if (i == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 {
2371 c = -1;
2372 break;
2373 }
2374 continue;
2375 }
2376 }
2377
2378/*
2379 * get a character: 3. from the user - handle <Esc> in Insert mode
2380 */
2381 /*
2382 * special case: if we get an <ESC> in insert mode and there
2383 * are no more characters at once, we pretend to go out of
2384 * insert mode. This prevents the one second delay after
2385 * typing an <ESC>. If we get something after all, we may
2386 * have to redisplay the mode. That the cursor is in the wrong
2387 * place does not matter.
2388 */
2389 c = 0;
2390#ifdef FEAT_CMDL_INFO
2391 new_wcol = curwin->w_wcol;
2392 new_wrow = curwin->w_wrow;
2393#endif
2394 if ( advance
2395 && typebuf.tb_len == 1
2396 && typebuf.tb_buf[typebuf.tb_off] == ESC
2397 && !no_mapping
2398#ifdef FEAT_EX_EXTRA
2399 && ex_normal_busy == 0
2400#endif
2401 && typebuf.tb_maplen == 0
2402 && (State & INSERT)
2403 && (p_timeout || (keylen == KL_PART_KEY && p_ttimeout))
2404 && (c = inchar(typebuf.tb_buf + typebuf.tb_off
2405 + typebuf.tb_len, 3, 25L,
2406 typebuf.tb_change_cnt)) == 0)
2407 {
2408 colnr_T col = 0, vcol;
2409 char_u *ptr;
2410
Bram Moolenaar28c258f2006-01-25 22:02:51 +00002411 if (mode_displayed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 {
2413 unshowmode(TRUE);
2414 mode_deleted = TRUE;
2415 }
2416#ifdef FEAT_GUI
2417 /* may show different cursor shape */
2418 if (gui.in_use)
2419 {
2420 int save_State;
2421
2422 save_State = State;
2423 State = NORMAL;
2424 gui_update_cursor(TRUE, FALSE);
2425 State = save_State;
2426 shape_changed = TRUE;
2427 }
2428#endif
2429 validate_cursor();
2430 old_wcol = curwin->w_wcol;
2431 old_wrow = curwin->w_wrow;
2432
2433 /* move cursor left, if possible */
2434 if (curwin->w_cursor.col != 0)
2435 {
2436 if (curwin->w_wcol > 0)
2437 {
2438 if (did_ai)
2439 {
2440 /*
2441 * We are expecting to truncate the trailing
2442 * white-space, so find the last non-white
2443 * character -- webb
2444 */
2445 col = vcol = curwin->w_wcol = 0;
2446 ptr = ml_get_curline();
2447 while (col < curwin->w_cursor.col)
2448 {
2449 if (!vim_iswhite(ptr[col]))
2450 curwin->w_wcol = vcol;
2451 vcol += lbr_chartabsize(ptr + col,
2452 (colnr_T)vcol);
2453#ifdef FEAT_MBYTE
2454 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002455 col += (*mb_ptr2len)(ptr + col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 else
2457#endif
2458 ++col;
2459 }
2460 curwin->w_wrow = curwin->w_cline_row
2461 + curwin->w_wcol / W_WIDTH(curwin);
2462 curwin->w_wcol %= W_WIDTH(curwin);
2463 curwin->w_wcol += curwin_col_off();
2464#ifdef FEAT_MBYTE
2465 col = 0; /* no correction needed */
2466#endif
2467 }
2468 else
2469 {
2470 --curwin->w_wcol;
2471#ifdef FEAT_MBYTE
2472 col = curwin->w_cursor.col - 1;
2473#endif
2474 }
2475 }
2476 else if (curwin->w_p_wrap && curwin->w_wrow)
2477 {
2478 --curwin->w_wrow;
2479 curwin->w_wcol = W_WIDTH(curwin) - 1;
2480#ifdef FEAT_MBYTE
2481 col = curwin->w_cursor.col - 1;
2482#endif
2483 }
2484#ifdef FEAT_MBYTE
2485 if (has_mbyte && col > 0 && curwin->w_wcol > 0)
2486 {
2487 /* Correct when the cursor is on the right halve
2488 * of a double-wide character. */
2489 ptr = ml_get_curline();
2490 col -= (*mb_head_off)(ptr, ptr + col);
2491 if ((*mb_ptr2cells)(ptr + col) > 1)
2492 --curwin->w_wcol;
2493 }
2494#endif
2495 }
2496 setcursor();
2497 out_flush();
2498#ifdef FEAT_CMDL_INFO
2499 new_wcol = curwin->w_wcol;
2500 new_wrow = curwin->w_wrow;
2501#endif
2502 curwin->w_wcol = old_wcol;
2503 curwin->w_wrow = old_wrow;
2504 }
2505 if (c < 0)
2506 continue; /* end of input script reached */
2507 typebuf.tb_len += c;
2508
2509 /* buffer full, don't map */
2510 if (typebuf.tb_len >= typebuf.tb_maplen + MAXMAPLEN)
2511 {
2512 timedout = TRUE;
2513 continue;
2514 }
2515
2516#ifdef FEAT_EX_EXTRA
2517 if (ex_normal_busy > 0)
2518 {
2519# ifdef FEAT_CMDWIN
2520 static int tc = 0;
2521# endif
2522
2523 /* No typeahead left and inside ":normal". Must return
2524 * something to avoid getting stuck. When an incomplete
2525 * mapping is present, behave like it timed out. */
2526 if (typebuf.tb_len > 0)
2527 {
2528 timedout = TRUE;
2529 continue;
2530 }
2531 /* When 'insertmode' is set, ESC just beeps in Insert
2532 * mode. Use CTRL-L to make edit() return.
2533 * For the command line only CTRL-C always breaks it.
2534 * For the cmdline window: Alternate between ESC and
2535 * CTRL-C: ESC for most situations and CTRL-C to close the
2536 * cmdline window. */
2537 if (p_im && (State & INSERT))
2538 c = Ctrl_L;
2539 else if ((State & CMDLINE)
2540# ifdef FEAT_CMDWIN
2541 || (cmdwin_type > 0 && tc == ESC)
2542# endif
2543 )
2544 c = Ctrl_C;
2545 else
2546 c = ESC;
2547# ifdef FEAT_CMDWIN
2548 tc = c;
2549# endif
2550 break;
2551 }
2552#endif
2553
2554/*
2555 * get a character: 3. from the user - update display
2556 */
2557 /* In insert mode a screen update is skipped when characters
2558 * are still available. But when those available characters
2559 * are part of a mapping, and we are going to do a blocking
2560 * wait here. Need to update the screen to display the
2561 * changed text so far. */
2562 if ((State & INSERT) && advance && must_redraw != 0)
2563 {
2564 update_screen(0);
2565 setcursor(); /* put cursor back where it belongs */
2566 }
2567
2568 /*
2569 * If we have a partial match (and are going to wait for more
2570 * input from the user), show the partially matched characters
2571 * to the user with showcmd.
2572 */
2573#ifdef FEAT_CMDL_INFO
2574 i = 0;
2575#endif
2576 c1 = 0;
2577 if (typebuf.tb_len > 0 && advance && !exmode_active)
2578 {
2579 if (((State & (NORMAL | INSERT)) || State == LANGMAP)
2580 && State != HITRETURN)
2581 {
2582 /* this looks nice when typing a dead character map */
2583 if (State & INSERT
2584 && ptr2cells(typebuf.tb_buf + typebuf.tb_off
2585 + typebuf.tb_len - 1) == 1)
2586 {
2587 edit_putchar(typebuf.tb_buf[typebuf.tb_off
2588 + typebuf.tb_len - 1], FALSE);
2589 setcursor(); /* put cursor back where it belongs */
2590 c1 = 1;
2591 }
2592#ifdef FEAT_CMDL_INFO
2593 /* need to use the col and row from above here */
2594 old_wcol = curwin->w_wcol;
2595 old_wrow = curwin->w_wrow;
2596 curwin->w_wcol = new_wcol;
2597 curwin->w_wrow = new_wrow;
2598 push_showcmd();
2599 if (typebuf.tb_len > SHOWCMD_COLS)
2600 i = typebuf.tb_len - SHOWCMD_COLS;
2601 while (i < typebuf.tb_len)
2602 (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off
2603 + i++]);
2604 curwin->w_wcol = old_wcol;
2605 curwin->w_wrow = old_wrow;
2606#endif
2607 }
2608
2609 /* this looks nice when typing a dead character map */
2610 if ((State & CMDLINE)
2611#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
2612 && cmdline_star == 0
2613#endif
2614 && ptr2cells(typebuf.tb_buf + typebuf.tb_off
2615 + typebuf.tb_len - 1) == 1)
2616 {
2617 putcmdline(typebuf.tb_buf[typebuf.tb_off
2618 + typebuf.tb_len - 1], FALSE);
2619 c1 = 1;
2620 }
2621 }
2622
2623/*
2624 * get a character: 3. from the user - get it
2625 */
Bram Moolenaar28a37ff2005-03-15 22:28:00 +00002626 wait_tb_len = typebuf.tb_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
2628 typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
2629 !advance
2630 ? 0
2631 : ((typebuf.tb_len == 0
2632 || !(p_timeout || (p_ttimeout
2633 && keylen == KL_PART_KEY)))
2634 ? -1L
2635 : ((keylen == KL_PART_KEY && p_ttm >= 0)
2636 ? p_ttm
2637 : p_tm)), typebuf.tb_change_cnt);
2638
2639#ifdef FEAT_CMDL_INFO
2640 if (i != 0)
2641 pop_showcmd();
2642#endif
2643 if (c1 == 1)
2644 {
2645 if (State & INSERT)
2646 edit_unputchar();
2647 if (State & CMDLINE)
2648 unputcmdline();
2649 setcursor(); /* put cursor back where it belongs */
2650 }
2651
2652 if (c < 0)
2653 continue; /* end of input script reached */
2654 if (c == NUL) /* no character available */
2655 {
2656 if (!advance)
2657 break;
Bram Moolenaar28a37ff2005-03-15 22:28:00 +00002658 if (wait_tb_len > 0) /* timed out */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659 {
2660 timedout = TRUE;
2661 continue;
2662 }
2663 }
2664 else
2665 { /* allow mapping for just typed characters */
2666 while (typebuf.tb_buf[typebuf.tb_off
2667 + typebuf.tb_len] != NUL)
2668 typebuf.tb_noremap[typebuf.tb_off
2669 + typebuf.tb_len++] = RM_YES;
2670#ifdef USE_IM_CONTROL
2671 /* Get IM status right after getting keys, not after the
2672 * timeout for a mapping (focus may be lost by then). */
2673 vgetc_im_active = im_get_status();
2674#endif
2675 }
2676 } /* for (;;) */
2677 } /* if (!character from stuffbuf) */
2678
2679 /* if advance is FALSE don't loop on NULs */
2680 } while (c < 0 || (advance && c == NUL));
2681
2682 /*
2683 * The "INSERT" message is taken care of here:
2684 * if we return an ESC to exit insert mode, the message is deleted
2685 * if we don't return an ESC but deleted the message before, redisplay it
2686 */
Bram Moolenaar09df3122006-01-23 22:23:09 +00002687 if (advance && p_smd && msg_silent == 0 && (State & INSERT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 {
Bram Moolenaar28c258f2006-01-25 22:02:51 +00002689 if (c == ESC && !mode_deleted && !no_mapping && mode_displayed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 {
2691 if (typebuf.tb_len && !KeyTyped)
2692 redraw_cmdline = TRUE; /* delete mode later */
2693 else
2694 unshowmode(FALSE);
2695 }
2696 else if (c != ESC && mode_deleted)
2697 {
2698 if (typebuf.tb_len && !KeyTyped)
2699 redraw_cmdline = TRUE; /* show mode later */
2700 else
2701 showmode();
2702 }
2703 }
2704#ifdef FEAT_GUI
2705 /* may unshow different cursor shape */
2706 if (gui.in_use && shape_changed)
2707 gui_update_cursor(TRUE, FALSE);
2708#endif
2709
Bram Moolenaar5555acc2006-04-07 21:33:12 +00002710 --vgetc_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711
2712 return c;
2713}
2714
2715/*
2716 * inchar() - get one character from
2717 * 1. a scriptfile
2718 * 2. the keyboard
2719 *
2720 * As much characters as we can get (upto 'maxlen') are put in "buf" and
2721 * NUL terminated (buffer length must be 'maxlen' + 1).
2722 * Minimum for "maxlen" is 3!!!!
2723 *
2724 * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
2725 * it. When typebuf.tb_change_cnt changes (e.g., when a message is received
2726 * from a remote client) "buf" can no longer be used. "tb_change_cnt" is 0
2727 * otherwise.
2728 *
2729 * If we got an interrupt all input is read until none is available.
2730 *
2731 * If wait_time == 0 there is no waiting for the char.
2732 * If wait_time == n we wait for n msec for a character to arrive.
2733 * If wait_time == -1 we wait forever for a character to arrive.
2734 *
2735 * Return the number of obtained characters.
2736 * Return -1 when end of input script reached.
2737 */
2738 int
2739inchar(buf, maxlen, wait_time, tb_change_cnt)
2740 char_u *buf;
2741 int maxlen;
2742 long wait_time; /* milli seconds */
2743 int tb_change_cnt;
2744{
2745 int len = 0; /* init for GCC */
2746 int retesc = FALSE; /* return ESC with gotint */
2747 int script_char;
2748
2749 if (wait_time == -1L || wait_time > 100L) /* flush output before waiting */
2750 {
2751 cursor_on();
2752 out_flush();
2753#ifdef FEAT_GUI
2754 if (gui.in_use)
2755 {
2756 gui_update_cursor(FALSE, FALSE);
2757# ifdef FEAT_MOUSESHAPE
2758 if (postponed_mouseshape)
2759 update_mouseshape(-1);
2760# endif
2761 }
2762#endif
2763 }
2764
2765 /*
2766 * Don't reset these when at the hit-return prompt, otherwise a endless
2767 * recursive loop may result (write error in swapfile, hit-return, timeout
2768 * on char wait, flush swapfile, write error....).
2769 */
2770 if (State != HITRETURN)
2771 {
2772 did_outofmem_msg = FALSE; /* display out of memory message (again) */
2773 did_swapwrite_msg = FALSE; /* display swap file write error again */
2774 }
2775 undo_off = FALSE; /* restart undo now */
2776
2777 /*
2778 * first try script file
2779 * If interrupted: Stop reading script files.
2780 */
2781 script_char = -1;
2782 while (scriptin[curscript] != NULL && script_char < 0)
2783 {
2784 if (got_int || (script_char = getc(scriptin[curscript])) < 0)
2785 {
2786 /* Reached EOF.
2787 * Careful: closescript() frees typebuf.tb_buf[] and buf[] may
2788 * point inside typebuf.tb_buf[]. Don't use buf[] after this! */
2789 closescript();
2790 /*
2791 * When reading script file is interrupted, return an ESC to get
2792 * back to normal mode.
2793 * Otherwise return -1, because typebuf.tb_buf[] has changed.
2794 */
2795 if (got_int)
2796 retesc = TRUE;
2797 else
2798 return -1;
2799 }
2800 else
2801 {
2802 buf[0] = script_char;
2803 len = 1;
2804 }
2805 }
2806
2807 if (script_char < 0) /* did not get a character from script */
2808 {
2809 /*
2810 * If we got an interrupt, skip all previously typed characters and
2811 * return TRUE if quit reading script file.
2812 * Stop reading typeahead when a single CTRL-C was read,
2813 * fill_input_buf() returns this when not able to read from stdin.
2814 * Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
2815 * and buf may be pointing inside typebuf.tb_buf[].
2816 */
2817 if (got_int)
2818 {
2819#define DUM_LEN MAXMAPLEN * 3 + 3
2820 char_u dum[DUM_LEN + 1];
2821
2822 for (;;)
2823 {
2824 len = ui_inchar(dum, DUM_LEN, 0L, 0);
2825 if (len == 0 || (len == 1 && dum[0] == 3))
2826 break;
2827 }
2828 return retesc;
2829 }
2830
2831 /*
2832 * Always flush the output characters when getting input characters
2833 * from the user.
2834 */
2835 out_flush();
2836
2837 /*
2838 * Fill up to a third of the buffer, because each character may be
2839 * tripled below.
2840 */
2841 len = ui_inchar(buf, maxlen / 3, wait_time, tb_change_cnt);
2842 }
2843
2844 if (typebuf_changed(tb_change_cnt))
2845 return 0;
2846
2847 return fix_input_buffer(buf, len, script_char >= 0);
2848}
2849
2850/*
2851 * Fix typed characters for use by vgetc() and check_termcode().
2852 * buf[] must have room to triple the number of bytes!
2853 * Returns the new length.
2854 */
2855 int
2856fix_input_buffer(buf, len, script)
2857 char_u *buf;
2858 int len;
2859 int script; /* TRUE when reading from a script */
2860{
2861 int i;
2862 char_u *p = buf;
2863
2864 /*
2865 * Two characters are special: NUL and K_SPECIAL.
2866 * When compiled With the GUI CSI is also special.
2867 * Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
2868 * Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
2869 * Replace CSI by K_SPECIAL KS_EXTRA KE_CSI
2870 * Don't replace K_SPECIAL when reading a script file.
2871 */
2872 for (i = len; --i >= 0; ++p)
2873 {
2874#ifdef FEAT_GUI
2875 /* When the GUI is used any character can come after a CSI, don't
2876 * escape it. */
2877 if (gui.in_use && p[0] == CSI && i >= 2)
2878 {
2879 p += 2;
2880 i -= 2;
2881 }
2882 /* When the GUI is not used CSI needs to be escaped. */
2883 else if (!gui.in_use && p[0] == CSI)
2884 {
2885 mch_memmove(p + 3, p + 1, (size_t)i);
2886 *p++ = K_SPECIAL;
2887 *p++ = KS_EXTRA;
2888 *p = (int)KE_CSI;
2889 len += 2;
2890 }
2891 else
2892#endif
2893 if (p[0] == NUL || (p[0] == K_SPECIAL && !script
Bram Moolenaar28a37ff2005-03-15 22:28:00 +00002894#ifdef FEAT_AUTOCMD
2895 /* timeout may generate K_CURSORHOLD */
2896 && (i < 2 || p[1] != KS_EXTRA || p[2] != (int)KE_CURSORHOLD)
2897#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898#if defined(WIN3264) && !defined(FEAT_GUI)
2899 /* Win32 console passes modifiers */
2900 && (i < 2 || p[1] != KS_MODIFIER)
2901#endif
2902 ))
2903 {
2904 mch_memmove(p + 3, p + 1, (size_t)i);
2905 p[2] = K_THIRD(p[0]);
2906 p[1] = K_SECOND(p[0]);
2907 p[0] = K_SPECIAL;
2908 p += 2;
2909 len += 2;
2910 }
2911 }
2912 *p = NUL; /* add trailing NUL */
2913 return len;
2914}
2915
2916#if defined(USE_INPUT_BUF) || defined(PROTO)
2917/*
2918 * Return TRUE when bytes are in the input buffer or in the typeahead buffer.
2919 * Normally the input buffer would be sufficient, but the server_to_input_buf()
2920 * may insert characters in the typeahead buffer while we are waiting for
2921 * input to arrive.
2922 */
2923 int
2924input_available()
2925{
2926 return (!vim_is_input_buf_empty()
2927# ifdef FEAT_CLIENTSERVER
2928 || received_from_client
2929# endif
2930 );
2931}
2932#endif
2933
2934/*
2935 * map[!] : show all key mappings
2936 * map[!] {lhs} : show key mapping for {lhs}
2937 * map[!] {lhs} {rhs} : set key mapping for {lhs} to {rhs}
2938 * noremap[!] {lhs} {rhs} : same, but no remapping for {rhs}
2939 * unmap[!] {lhs} : remove key mapping for {lhs}
2940 * abbr : show all abbreviations
2941 * abbr {lhs} : show abbreviations for {lhs}
2942 * abbr {lhs} {rhs} : set abbreviation for {lhs} to {rhs}
2943 * noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
2944 * unabbr {lhs} : remove abbreviation for {lhs}
2945 *
2946 * maptype: 0 for :map, 1 for :unmap, 2 for noremap.
2947 *
2948 * arg is pointer to any arguments. Note: arg cannot be a read-only string,
2949 * it will be modified.
2950 *
Bram Moolenaar371d5402006-03-20 21:47:49 +00002951 * for :map mode is NORMAL + VISUAL + SELECTMODE + OP_PENDING
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 * for :map! mode is INSERT + CMDLINE
2953 * for :cmap mode is CMDLINE
2954 * for :imap mode is INSERT
2955 * for :lmap mode is LANGMAP
2956 * for :nmap mode is NORMAL
Bram Moolenaar371d5402006-03-20 21:47:49 +00002957 * for :vmap mode is VISUAL + SELECTMODE
2958 * for :xmap mode is VISUAL
2959 * for :smap mode is SELECTMODE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 * for :omap mode is OP_PENDING
2961 *
2962 * for :abbr mode is INSERT + CMDLINE
2963 * for :iabbr mode is INSERT
2964 * for :cabbr mode is CMDLINE
2965 *
2966 * Return 0 for success
2967 * 1 for invalid arguments
2968 * 2 for no match
2969 * 4 for out of mem
2970 * 5 for entry not unique
2971 */
2972 int
2973do_map(maptype, arg, mode, abbrev)
2974 int maptype;
2975 char_u *arg;
2976 int mode;
2977 int abbrev; /* not a mapping but an abbreviation */
2978{
2979 char_u *keys;
2980 mapblock_T *mp, **mpp;
2981 char_u *rhs;
2982 char_u *p;
2983 int n;
2984 int len = 0; /* init for GCC */
2985 char_u *newstr;
2986 int hasarg;
2987 int haskey;
2988 int did_it = FALSE;
2989#ifdef FEAT_LOCALMAP
2990 int did_local = FALSE;
2991#endif
2992 int round;
2993 char_u *keys_buf = NULL;
2994 char_u *arg_buf = NULL;
2995 int retval = 0;
2996 int do_backslash;
2997 int hash;
2998 int new_hash;
2999 mapblock_T **abbr_table;
3000 mapblock_T **map_table;
3001 int unique = FALSE;
3002 int silent = FALSE;
Bram Moolenaar4e427192006-03-10 21:34:27 +00003003#ifdef FEAT_EVAL
3004 int expr = FALSE;
3005#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 int noremap;
3007
3008 keys = arg;
3009 map_table = maphash;
3010 abbr_table = &first_abbr;
3011
3012 /* For ":noremap" don't remap, otherwise do remap. */
3013 if (maptype == 2)
3014 noremap = REMAP_NONE;
3015 else
3016 noremap = REMAP_YES;
3017
Bram Moolenaar4e427192006-03-10 21:34:27 +00003018 /* Accept <buffer>, <silent>, <expr> <script> and <unique> in any order. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 for (;;)
3020 {
3021#ifdef FEAT_LOCALMAP
3022 /*
3023 * Check for "<buffer>": mapping local to buffer.
3024 */
3025 if (STRNCMP(keys, "<buffer>", 8) == 0)
3026 {
3027 keys = skipwhite(keys + 8);
3028 map_table = curbuf->b_maphash;
3029 abbr_table = &curbuf->b_first_abbr;
3030 continue;
3031 }
3032#endif
3033
3034 /*
3035 * Check for "<silent>": don't echo commands.
3036 */
3037 if (STRNCMP(keys, "<silent>", 8) == 0)
3038 {
3039 keys = skipwhite(keys + 8);
3040 silent = TRUE;
3041 continue;
3042 }
3043
3044#ifdef FEAT_EVAL
3045 /*
3046 * Check for "<script>": remap script-local mappings only
3047 */
3048 if (STRNCMP(keys, "<script>", 8) == 0)
3049 {
3050 keys = skipwhite(keys + 8);
3051 noremap = REMAP_SCRIPT;
3052 continue;
3053 }
Bram Moolenaar4e427192006-03-10 21:34:27 +00003054
3055 /*
3056 * Check for "<expr>": {rhs} is an expression.
3057 */
3058 if (STRNCMP(keys, "<expr>", 6) == 0)
3059 {
3060 keys = skipwhite(keys + 6);
3061 expr = TRUE;
3062 continue;
3063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064#endif
3065 /*
3066 * Check for "<unique>": don't overwrite an existing mapping.
3067 */
3068 if (STRNCMP(keys, "<unique>", 8) == 0)
3069 {
3070 keys = skipwhite(keys + 8);
3071 unique = TRUE;
3072 continue;
3073 }
3074 break;
3075 }
3076
3077 validate_maphash();
3078
3079 /*
3080 * find end of keys and skip CTRL-Vs (and backslashes) in it
3081 * Accept backslash like CTRL-V when 'cpoptions' does not contain 'B'.
3082 * with :unmap white space is included in the keys, no argument possible
3083 */
3084 p = keys;
3085 do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
3086 while (*p && (maptype == 1 || !vim_iswhite(*p)))
3087 {
3088 if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) &&
3089 p[1] != NUL)
3090 ++p; /* skip CTRL-V or backslash */
3091 ++p;
3092 }
3093 if (*p != NUL)
3094 *p++ = NUL;
3095 p = skipwhite(p);
3096 rhs = p;
3097 hasarg = (*rhs != NUL);
3098 haskey = (*keys != NUL);
3099
3100 /* check for :unmap without argument */
3101 if (maptype == 1 && !haskey)
3102 {
3103 retval = 1;
3104 goto theend;
3105 }
3106
3107 /*
3108 * If mapping has been given as ^V<C_UP> say, then replace the term codes
3109 * with the appropriate two bytes. If it is a shifted special key, unshift
3110 * it too, giving another two bytes.
3111 * replace_termcodes() may move the result to allocated memory, which
3112 * needs to be freed later (*keys_buf and *arg_buf).
3113 * replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
3114 */
3115 if (haskey)
3116 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE);
3117 if (hasarg)
3118 {
3119 if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */
3120 rhs = (char_u *)"";
3121 else
3122 rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE);
3123 }
3124
3125#ifdef FEAT_FKMAP
3126 /*
3127 * when in right-to-left mode and alternate keymap option set,
3128 * reverse the character flow in the rhs in Farsi.
3129 */
3130 if (p_altkeymap && curwin->w_p_rl)
3131 lrswap(rhs);
3132#endif
3133
3134 /*
3135 * check arguments and translate function keys
3136 */
3137 if (haskey)
3138 {
3139 len = (int)STRLEN(keys);
3140 if (len > MAXMAPLEN) /* maximum length of MAXMAPLEN chars */
3141 {
3142 retval = 1;
3143 goto theend;
3144 }
3145
3146 if (abbrev && maptype != 1)
3147 {
3148 /*
3149 * If an abbreviation ends in a keyword character, the
3150 * rest must be all keyword-char or all non-keyword-char.
3151 * Otherwise we won't be able to find the start of it in a
3152 * vi-compatible way.
3153 */
3154#ifdef FEAT_MBYTE
3155 if (has_mbyte)
3156 {
3157 int first, last;
3158 int same = -1;
3159
3160 first = vim_iswordp(keys);
3161 last = first;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003162 p = keys + (*mb_ptr2len)(keys);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 n = 1;
3164 while (p < keys + len)
3165 {
3166 ++n; /* nr of (multi-byte) chars */
3167 last = vim_iswordp(p); /* type of last char */
3168 if (same == -1 && last != first)
3169 same = n - 1; /* count of same char type */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003170 p += (*mb_ptr2len)(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 }
3172 if (last && n > 2 && same >= 0 && same < n - 1)
3173 {
3174 retval = 1;
3175 goto theend;
3176 }
3177 }
3178 else
3179#endif
3180 if (vim_iswordc(keys[len - 1])) /* ends in keyword char */
3181 for (n = 0; n < len - 2; ++n)
3182 if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
3183 {
3184 retval = 1;
3185 goto theend;
3186 }
3187 /* An abbrevation cannot contain white space. */
3188 for (n = 0; n < len; ++n)
3189 if (vim_iswhite(keys[n]))
3190 {
3191 retval = 1;
3192 goto theend;
3193 }
3194 }
3195 }
3196
3197 if (haskey && hasarg && abbrev) /* if we will add an abbreviation */
3198 no_abbr = FALSE; /* reset flag that indicates there are
3199 no abbreviations */
3200
3201 if (!haskey || (maptype != 1 && !hasarg))
3202 msg_start();
3203
3204#ifdef FEAT_LOCALMAP
3205 /*
3206 * Check if a new local mapping wasn't already defined globally.
3207 */
3208 if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
3209 {
3210 /* need to loop over all global hash lists */
3211 for (hash = 0; hash < 256 && !got_int; ++hash)
3212 {
3213 if (abbrev)
3214 {
3215 if (hash != 0) /* there is only one abbreviation list */
3216 break;
3217 mp = first_abbr;
3218 }
3219 else
3220 mp = maphash[hash];
3221 for ( ; mp != NULL && !got_int; mp = mp->m_next)
3222 {
3223 /* check entries with the same mode */
3224 if ((mp->m_mode & mode) != 0
3225 && mp->m_keylen == len
3226 && unique
3227 && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
3228 {
3229 if (abbrev)
3230 EMSG2(_("E224: global abbreviation already exists for %s"),
3231 mp->m_keys);
3232 else
3233 EMSG2(_("E225: global mapping already exists for %s"),
3234 mp->m_keys);
3235 retval = 5;
3236 goto theend;
3237 }
3238 }
3239 }
3240 }
3241
3242 /*
3243 * When listing global mappings, also list buffer-local ones here.
3244 */
3245 if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
3246 {
3247 /* need to loop over all global hash lists */
3248 for (hash = 0; hash < 256 && !got_int; ++hash)
3249 {
3250 if (abbrev)
3251 {
3252 if (hash != 0) /* there is only one abbreviation list */
3253 break;
3254 mp = curbuf->b_first_abbr;
3255 }
3256 else
3257 mp = curbuf->b_maphash[hash];
3258 for ( ; mp != NULL && !got_int; mp = mp->m_next)
3259 {
3260 /* check entries with the same mode */
3261 if ((mp->m_mode & mode) != 0)
3262 {
3263 if (!haskey) /* show all entries */
3264 {
3265 showmap(mp, TRUE);
3266 did_local = TRUE;
3267 }
3268 else
3269 {
3270 n = mp->m_keylen;
3271 if (STRNCMP(mp->m_keys, keys,
3272 (size_t)(n < len ? n : len)) == 0)
3273 {
3274 showmap(mp, TRUE);
3275 did_local = TRUE;
3276 }
3277 }
3278 }
3279 }
3280 }
3281 }
3282#endif
3283
3284 /*
3285 * Find an entry in the maphash[] list that matches.
3286 * For :unmap we may loop two times: once to try to unmap an entry with a
3287 * matching 'from' part, a second time, if the first fails, to unmap an
3288 * entry with a matching 'to' part. This was done to allow ":ab foo bar"
3289 * to be unmapped by typing ":unab foo", where "foo" will be replaced by
3290 * "bar" because of the abbreviation.
3291 */
3292 for (round = 0; (round == 0 || maptype == 1) && round <= 1
3293 && !did_it && !got_int; ++round)
3294 {
3295 /* need to loop over all hash lists */
3296 for (hash = 0; hash < 256 && !got_int; ++hash)
3297 {
3298 if (abbrev)
3299 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003300 if (hash > 0) /* there is only one abbreviation list */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 break;
3302 mpp = abbr_table;
3303 }
3304 else
3305 mpp = &(map_table[hash]);
3306 for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
3307 {
3308
3309 if (!(mp->m_mode & mode)) /* skip entries with wrong mode */
3310 {
3311 mpp = &(mp->m_next);
3312 continue;
3313 }
3314 if (!haskey) /* show all entries */
3315 {
3316 showmap(mp, map_table != maphash);
3317 did_it = TRUE;
3318 }
3319 else /* do we have a match? */
3320 {
3321 if (round) /* second round: Try unmap "rhs" string */
3322 {
3323 n = (int)STRLEN(mp->m_str);
3324 p = mp->m_str;
3325 }
3326 else
3327 {
3328 n = mp->m_keylen;
3329 p = mp->m_keys;
3330 }
3331 if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
3332 {
3333 if (maptype == 1) /* delete entry */
3334 {
3335 /* Only accept a full match. For abbreviations we
3336 * ignore trailing space when matching with the
3337 * "lhs", since an abbreviation can't have
3338 * trailing space. */
3339 if (n != len && (!abbrev || round || n > len
3340 || *skipwhite(keys + n) != NUL))
3341 {
3342 mpp = &(mp->m_next);
3343 continue;
3344 }
3345 /*
3346 * We reset the indicated mode bits. If nothing is
3347 * left the entry is deleted below.
3348 */
3349 mp->m_mode &= ~mode;
3350 did_it = TRUE; /* remember we did something */
3351 }
3352 else if (!hasarg) /* show matching entry */
3353 {
3354 showmap(mp, map_table != maphash);
3355 did_it = TRUE;
3356 }
3357 else if (n != len) /* new entry is ambigious */
3358 {
3359 mpp = &(mp->m_next);
3360 continue;
3361 }
3362 else if (unique)
3363 {
3364 if (abbrev)
3365 EMSG2(_("E226: abbreviation already exists for %s"),
3366 p);
3367 else
3368 EMSG2(_("E227: mapping already exists for %s"), p);
3369 retval = 5;
3370 goto theend;
3371 }
3372 else /* new rhs for existing entry */
3373 {
3374 mp->m_mode &= ~mode; /* remove mode bits */
3375 if (mp->m_mode == 0 && !did_it) /* reuse entry */
3376 {
3377 newstr = vim_strsave(rhs);
3378 if (newstr == NULL)
3379 {
3380 retval = 4; /* no mem */
3381 goto theend;
3382 }
3383 vim_free(mp->m_str);
3384 mp->m_str = newstr;
3385 mp->m_noremap = noremap;
3386 mp->m_silent = silent;
3387 mp->m_mode = mode;
Bram Moolenaarae5bce12005-08-15 21:41:48 +00003388#ifdef FEAT_EVAL
Bram Moolenaar4e427192006-03-10 21:34:27 +00003389 mp->m_expr = expr;
Bram Moolenaarae5bce12005-08-15 21:41:48 +00003390 mp->m_script_ID = current_SID;
3391#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 did_it = TRUE;
3393 }
3394 }
3395 if (mp->m_mode == 0) /* entry can be deleted */
3396 {
3397 map_free(mpp);
3398 continue; /* continue with *mpp */
3399 }
3400
3401 /*
3402 * May need to put this entry into another hash list.
3403 */
3404 new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
3405 if (!abbrev && new_hash != hash)
3406 {
3407 *mpp = mp->m_next;
3408 mp->m_next = map_table[new_hash];
3409 map_table[new_hash] = mp;
3410
3411 continue; /* continue with *mpp */
3412 }
3413 }
3414 }
3415 mpp = &(mp->m_next);
3416 }
3417 }
3418 }
3419
3420 if (maptype == 1) /* delete entry */
3421 {
3422 if (!did_it)
3423 retval = 2; /* no match */
3424 goto theend;
3425 }
3426
3427 if (!haskey || !hasarg) /* print entries */
3428 {
3429 if (!did_it
3430#ifdef FEAT_LOCALMAP
3431 && !did_local
3432#endif
3433 )
3434 {
3435 if (abbrev)
3436 MSG(_("No abbreviation found"));
3437 else
3438 MSG(_("No mapping found"));
3439 }
3440 goto theend; /* listing finished */
3441 }
3442
3443 if (did_it) /* have added the new entry already */
3444 goto theend;
3445
3446 /*
3447 * Get here when adding a new entry to the maphash[] list or abbrlist.
3448 */
3449 mp = (mapblock_T *)alloc((unsigned)sizeof(mapblock_T));
3450 if (mp == NULL)
3451 {
3452 retval = 4; /* no mem */
3453 goto theend;
3454 }
3455
3456 /* If CTRL-C has been mapped, don't always use it for Interrupting */
3457 if (*keys == Ctrl_C)
3458 mapped_ctrl_c = TRUE;
3459
3460 mp->m_keys = vim_strsave(keys);
3461 mp->m_str = vim_strsave(rhs);
3462 if (mp->m_keys == NULL || mp->m_str == NULL)
3463 {
3464 vim_free(mp->m_keys);
3465 vim_free(mp->m_str);
3466 vim_free(mp);
3467 retval = 4; /* no mem */
3468 goto theend;
3469 }
3470 mp->m_keylen = (int)STRLEN(mp->m_keys);
3471 mp->m_noremap = noremap;
3472 mp->m_silent = silent;
3473 mp->m_mode = mode;
Bram Moolenaarae5bce12005-08-15 21:41:48 +00003474#ifdef FEAT_EVAL
Bram Moolenaar4e427192006-03-10 21:34:27 +00003475 mp->m_expr = expr;
Bram Moolenaarae5bce12005-08-15 21:41:48 +00003476 mp->m_script_ID = current_SID;
3477#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478
3479 /* add the new entry in front of the abbrlist or maphash[] list */
3480 if (abbrev)
3481 {
3482 mp->m_next = *abbr_table;
3483 *abbr_table = mp;
3484 }
3485 else
3486 {
3487 n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
3488 mp->m_next = map_table[n];
3489 map_table[n] = mp;
3490 }
3491
3492theend:
3493 vim_free(keys_buf);
3494 vim_free(arg_buf);
3495 return retval;
3496}
3497
3498/*
3499 * Delete one entry from the abbrlist or maphash[].
3500 * "mpp" is a pointer to the m_next field of the PREVIOUS entry!
3501 */
3502 static void
3503map_free(mpp)
3504 mapblock_T **mpp;
3505{
3506 mapblock_T *mp;
3507
3508 mp = *mpp;
3509 vim_free(mp->m_keys);
3510 vim_free(mp->m_str);
3511 *mpp = mp->m_next;
3512 vim_free(mp);
3513}
3514
3515/*
3516 * Initialize maphash[] for first use.
3517 */
3518 static void
3519validate_maphash()
3520{
3521 if (!maphash_valid)
3522 {
3523 vim_memset(maphash, 0, sizeof(maphash));
3524 maphash_valid = TRUE;
3525 }
3526}
3527
3528/*
3529 * Get the mapping mode from the command name.
3530 */
3531 int
3532get_map_mode(cmdp, forceit)
3533 char_u **cmdp;
3534 int forceit;
3535{
3536 char_u *p;
3537 int modec;
3538 int mode;
3539
3540 p = *cmdp;
3541 modec = *p++;
3542 if (modec == 'i')
3543 mode = INSERT; /* :imap */
3544 else if (modec == 'l')
3545 mode = LANGMAP; /* :lmap */
3546 else if (modec == 'c')
3547 mode = CMDLINE; /* :cmap */
3548 else if (modec == 'n' && *p != 'o') /* avoid :noremap */
3549 mode = NORMAL; /* :nmap */
3550 else if (modec == 'v')
Bram Moolenaar371d5402006-03-20 21:47:49 +00003551 mode = VISUAL + SELECTMODE; /* :vmap */
3552 else if (modec == 'x')
3553 mode = VISUAL; /* :xmap */
3554 else if (modec == 's')
3555 mode = SELECTMODE; /* :smap */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556 else if (modec == 'o')
3557 mode = OP_PENDING; /* :omap */
3558 else
3559 {
3560 --p;
3561 if (forceit)
3562 mode = INSERT + CMDLINE; /* :map ! */
3563 else
Bram Moolenaar371d5402006-03-20 21:47:49 +00003564 mode = VISUAL + SELECTMODE + NORMAL + OP_PENDING;/* :map */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 }
3566
3567 *cmdp = p;
3568 return mode;
3569}
3570
3571/*
3572 * Clear all mappings or abbreviations.
3573 * 'abbr' should be FALSE for mappings, TRUE for abbreviations.
3574 */
3575/*ARGSUSED*/
3576 void
3577map_clear(cmdp, arg, forceit, abbr)
3578 char_u *cmdp;
3579 char_u *arg;
3580 int forceit;
3581 int abbr;
3582{
3583 int mode;
3584#ifdef FEAT_LOCALMAP
3585 int local;
3586
3587 local = (STRCMP(arg, "<buffer>") == 0);
3588 if (!local && *arg != NUL)
3589 {
3590 EMSG(_(e_invarg));
3591 return;
3592 }
3593#endif
3594
3595 mode = get_map_mode(&cmdp, forceit);
3596 map_clear_int(curbuf, mode,
3597#ifdef FEAT_LOCALMAP
3598 local,
3599#else
3600 FALSE,
3601#endif
3602 abbr);
3603}
3604
3605/*
3606 * Clear all mappings in "mode".
3607 */
3608/*ARGSUSED*/
3609 void
3610map_clear_int(buf, mode, local, abbr)
3611 buf_T *buf; /* buffer for local mappings */
3612 int mode; /* mode in which to delete */
3613 int local; /* TRUE for buffer-local mappings */
3614 int abbr; /* TRUE for abbreviations */
3615{
3616 mapblock_T *mp, **mpp;
3617 int hash;
3618 int new_hash;
3619
3620 validate_maphash();
3621
3622 for (hash = 0; hash < 256; ++hash)
3623 {
3624 if (abbr)
3625 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003626 if (hash > 0) /* there is only one abbrlist */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627 break;
3628#ifdef FEAT_LOCALMAP
3629 if (local)
3630 mpp = &buf->b_first_abbr;
3631 else
3632#endif
3633 mpp = &first_abbr;
3634 }
3635 else
3636 {
3637#ifdef FEAT_LOCALMAP
3638 if (local)
3639 mpp = &buf->b_maphash[hash];
3640 else
3641#endif
3642 mpp = &maphash[hash];
3643 }
3644 while (*mpp != NULL)
3645 {
3646 mp = *mpp;
3647 if (mp->m_mode & mode)
3648 {
3649 mp->m_mode &= ~mode;
3650 if (mp->m_mode == 0) /* entry can be deleted */
3651 {
3652 map_free(mpp);
3653 continue;
3654 }
3655 /*
3656 * May need to put this entry into another hash list.
3657 */
3658 new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
3659 if (!abbr && new_hash != hash)
3660 {
3661 *mpp = mp->m_next;
3662#ifdef FEAT_LOCALMAP
3663 if (local)
3664 {
3665 mp->m_next = buf->b_maphash[new_hash];
3666 buf->b_maphash[new_hash] = mp;
3667 }
3668 else
3669#endif
3670 {
3671 mp->m_next = maphash[new_hash];
3672 maphash[new_hash] = mp;
3673 }
3674 continue; /* continue with *mpp */
3675 }
3676 }
3677 mpp = &(mp->m_next);
3678 }
3679 }
3680}
3681
3682 static void
3683showmap(mp, local)
3684 mapblock_T *mp;
3685 int local; /* TRUE for buffer-local map */
3686{
3687 int len = 1;
3688
3689 if (msg_didout || msg_silent != 0)
3690 msg_putchar('\n');
3691 if ((mp->m_mode & (INSERT + CMDLINE)) == INSERT + CMDLINE)
3692 msg_putchar('!'); /* :map! */
3693 else if (mp->m_mode & INSERT)
3694 msg_putchar('i'); /* :imap */
3695 else if (mp->m_mode & LANGMAP)
3696 msg_putchar('l'); /* :lmap */
3697 else if (mp->m_mode & CMDLINE)
3698 msg_putchar('c'); /* :cmap */
Bram Moolenaar371d5402006-03-20 21:47:49 +00003699 else if ((mp->m_mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING))
3700 == NORMAL + VISUAL + SELECTMODE + OP_PENDING)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 msg_putchar(' '); /* :map */
3702 else
3703 {
3704 len = 0;
3705 if (mp->m_mode & NORMAL)
3706 {
3707 msg_putchar('n'); /* :nmap */
3708 ++len;
3709 }
3710 if (mp->m_mode & OP_PENDING)
3711 {
3712 msg_putchar('o'); /* :omap */
3713 ++len;
3714 }
Bram Moolenaar371d5402006-03-20 21:47:49 +00003715 if ((mp->m_mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 {
3717 msg_putchar('v'); /* :vmap */
3718 ++len;
3719 }
Bram Moolenaar371d5402006-03-20 21:47:49 +00003720 else
3721 {
3722 if (mp->m_mode & VISUAL)
3723 {
3724 msg_putchar('x'); /* :xmap */
3725 ++len;
3726 }
3727 if (mp->m_mode & SELECTMODE)
3728 {
3729 msg_putchar('s'); /* :smap */
3730 ++len;
3731 }
3732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 }
3734 while (++len <= 3)
3735 msg_putchar(' ');
3736
3737 /* Get length of what we write */
3738 len = msg_outtrans_special(mp->m_keys, TRUE);
3739 do
3740 {
3741 msg_putchar(' '); /* padd with blanks */
3742 ++len;
3743 } while (len < 12);
3744
3745 if (mp->m_noremap == REMAP_NONE)
3746 msg_puts_attr((char_u *)"*", hl_attr(HLF_8));
3747 else if (mp->m_noremap == REMAP_SCRIPT)
3748 msg_puts_attr((char_u *)"&", hl_attr(HLF_8));
3749 else
3750 msg_putchar(' ');
3751
3752 if (local)
3753 msg_putchar('@');
3754 else
3755 msg_putchar(' ');
3756
3757 /* Use FALSE below if we only want things like <Up> to show up as such on
3758 * the rhs, and not M-x etc, TRUE gets both -- webb
3759 */
3760 if (*mp->m_str == NUL)
3761 msg_puts_attr((char_u *)"<Nop>", hl_attr(HLF_8));
3762 else
3763 msg_outtrans_special(mp->m_str, FALSE);
Bram Moolenaarae5bce12005-08-15 21:41:48 +00003764#ifdef FEAT_EVAL
3765 if (p_verbose > 0)
3766 last_set_msg(mp->m_script_ID);
3767#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768 out_flush(); /* show one line at a time */
3769}
3770
3771#if defined(FEAT_EVAL) || defined(PROTO)
3772/*
3773 * Return TRUE if a map exists that has "str" in the rhs for mode "modechars".
3774 * Recognize termcap codes in "str".
3775 * Also checks mappings local to the current buffer.
3776 */
3777 int
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003778map_to_exists(str, modechars, abbr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003779 char_u *str;
3780 char_u *modechars;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003781 int abbr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782{
3783 int mode = 0;
3784 char_u *rhs;
3785 char_u *buf;
3786 int retval;
3787
3788 rhs = replace_termcodes(str, &buf, FALSE, TRUE);
3789
3790 if (vim_strchr(modechars, 'n') != NULL)
3791 mode |= NORMAL;
3792 if (vim_strchr(modechars, 'v') != NULL)
Bram Moolenaar371d5402006-03-20 21:47:49 +00003793 mode |= VISUAL + SELECTMODE;
3794 if (vim_strchr(modechars, 'x') != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 mode |= VISUAL;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003796 if (vim_strchr(modechars, 's') != NULL)
3797 mode |= SELECTMODE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 if (vim_strchr(modechars, 'o') != NULL)
3799 mode |= OP_PENDING;
3800 if (vim_strchr(modechars, 'i') != NULL)
3801 mode |= INSERT;
3802 if (vim_strchr(modechars, 'l') != NULL)
3803 mode |= LANGMAP;
3804 if (vim_strchr(modechars, 'c') != NULL)
3805 mode |= CMDLINE;
3806
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003807 retval = map_to_exists_mode(rhs, mode, abbr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 vim_free(buf);
3809
3810 return retval;
3811}
3812#endif
3813
3814/*
3815 * Return TRUE if a map exists that has "str" in the rhs for mode "mode".
3816 * Also checks mappings local to the current buffer.
3817 */
3818 int
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003819map_to_exists_mode(rhs, mode, abbr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 char_u *rhs;
3821 int mode;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003822 int abbr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823{
3824 mapblock_T *mp;
3825 int hash;
3826# ifdef FEAT_LOCALMAP
3827 int expand_buffer = FALSE;
3828
3829 validate_maphash();
3830
3831 /* Do it twice: once for global maps and once for local maps. */
3832 for (;;)
3833 {
3834# endif
3835 for (hash = 0; hash < 256; ++hash)
3836 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003837 if (abbr)
3838 {
3839 if (hash > 0) /* there is only one abbr list */
3840 break;
3841#ifdef FEAT_LOCALMAP
3842 if (expand_buffer)
3843 mp = curbuf->b_first_abbr;
3844 else
3845#endif
3846 mp = first_abbr;
3847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848# ifdef FEAT_LOCALMAP
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003849 else if (expand_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 mp = curbuf->b_maphash[hash];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851# endif
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003852 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853 mp = maphash[hash];
3854 for (; mp; mp = mp->m_next)
3855 {
3856 if ((mp->m_mode & mode)
3857 && strstr((char *)mp->m_str, (char *)rhs) != NULL)
3858 return TRUE;
3859 }
3860 }
3861# ifdef FEAT_LOCALMAP
3862 if (expand_buffer)
3863 break;
3864 expand_buffer = TRUE;
3865 }
3866# endif
3867
3868 return FALSE;
3869}
3870
3871#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
3872/*
3873 * Used below when expanding mapping/abbreviation names.
3874 */
3875static int expand_mapmodes = 0;
3876static int expand_isabbrev = 0;
3877#ifdef FEAT_LOCALMAP
3878static int expand_buffer = FALSE;
3879#endif
3880
3881/*
3882 * Work out what to complete when doing command line completion of mapping
3883 * or abbreviation names.
3884 */
3885 char_u *
3886set_context_in_map_cmd(xp, cmd, arg, forceit, isabbrev, isunmap, cmdidx)
3887 expand_T *xp;
3888 char_u *cmd;
3889 char_u *arg;
3890 int forceit; /* TRUE if '!' given */
3891 int isabbrev; /* TRUE if abbreviation */
3892 int isunmap; /* TRUE if unmap/unabbrev command */
3893 cmdidx_T cmdidx;
3894{
3895 if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap)
3896 xp->xp_context = EXPAND_NOTHING;
3897 else
3898 {
3899 if (isunmap)
3900 expand_mapmodes = get_map_mode(&cmd, forceit || isabbrev);
3901 else
3902 {
3903 expand_mapmodes = INSERT + CMDLINE;
3904 if (!isabbrev)
Bram Moolenaar371d5402006-03-20 21:47:49 +00003905 expand_mapmodes += VISUAL + SELECTMODE + NORMAL + OP_PENDING;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 }
3907 expand_isabbrev = isabbrev;
3908 xp->xp_context = EXPAND_MAPPINGS;
3909#ifdef FEAT_LOCALMAP
3910 expand_buffer = FALSE;
3911#endif
3912 for (;;)
3913 {
3914#ifdef FEAT_LOCALMAP
3915 if (STRNCMP(arg, "<buffer>", 8) == 0)
3916 {
3917 expand_buffer = TRUE;
3918 arg = skipwhite(arg + 8);
3919 continue;
3920 }
3921#endif
3922 if (STRNCMP(arg, "<unique>", 8) == 0)
3923 {
3924 arg = skipwhite(arg + 8);
3925 continue;
3926 }
3927 if (STRNCMP(arg, "<silent>", 8) == 0)
3928 {
3929 arg = skipwhite(arg + 8);
3930 continue;
3931 }
Bram Moolenaar4e427192006-03-10 21:34:27 +00003932#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 if (STRNCMP(arg, "<script>", 8) == 0)
3934 {
3935 arg = skipwhite(arg + 8);
3936 continue;
3937 }
Bram Moolenaar4e427192006-03-10 21:34:27 +00003938 if (STRNCMP(arg, "<expr>", 6) == 0)
3939 {
3940 arg = skipwhite(arg + 6);
3941 continue;
3942 }
3943#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 break;
3945 }
3946 xp->xp_pattern = arg;
3947 }
3948
3949 return NULL;
3950}
3951
3952/*
3953 * Find all mapping/abbreviation names that match regexp 'prog'.
3954 * For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
3955 * Return OK if matches found, FAIL otherwise.
3956 */
3957 int
3958ExpandMappings(regmatch, num_file, file)
3959 regmatch_T *regmatch;
3960 int *num_file;
3961 char_u ***file;
3962{
3963 mapblock_T *mp;
3964 int hash;
3965 int count;
3966 int round;
3967 char_u *p;
3968 int i;
3969
3970 validate_maphash();
3971
3972 *num_file = 0; /* return values in case of FAIL */
3973 *file = NULL;
3974
3975 /*
3976 * round == 1: Count the matches.
3977 * round == 2: Build the array to keep the matches.
3978 */
3979 for (round = 1; round <= 2; ++round)
3980 {
3981 count = 0;
3982
Bram Moolenaar4e427192006-03-10 21:34:27 +00003983 for (i = 0; i < 5; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 {
3985 if (i == 0)
3986 p = (char_u *)"<silent>";
3987 else if (i == 1)
3988 p = (char_u *)"<unique>";
3989#ifdef FEAT_EVAL
3990 else if (i == 2)
3991 p = (char_u *)"<script>";
Bram Moolenaar4e427192006-03-10 21:34:27 +00003992 else if (i == 3)
3993 p = (char_u *)"<expr>";
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994#endif
3995#ifdef FEAT_LOCALMAP
Bram Moolenaar4e427192006-03-10 21:34:27 +00003996 else if (i == 4 && !expand_buffer)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 p = (char_u *)"<buffer>";
3998#endif
3999 else
4000 continue;
4001
4002 if (vim_regexec(regmatch, p, (colnr_T)0))
4003 {
4004 if (round == 1)
4005 ++count;
4006 else
4007 (*file)[count++] = vim_strsave(p);
4008 }
4009 }
4010
4011 for (hash = 0; hash < 256; ++hash)
4012 {
4013 if (expand_isabbrev)
4014 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004015 if (hash > 0) /* only one abbrev list */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 break; /* for (hash) */
4017 mp = first_abbr;
4018 }
4019#ifdef FEAT_LOCALMAP
4020 else if (expand_buffer)
4021 mp = curbuf->b_maphash[hash];
4022#endif
4023 else
4024 mp = maphash[hash];
4025 for (; mp; mp = mp->m_next)
4026 {
4027 if (mp->m_mode & expand_mapmodes)
4028 {
4029 p = translate_mapping(mp->m_keys, TRUE);
4030 if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0))
4031 {
4032 if (round == 1)
4033 ++count;
4034 else
4035 {
4036 (*file)[count++] = p;
4037 p = NULL;
4038 }
4039 }
4040 vim_free(p);
4041 }
4042 } /* for (mp) */
4043 } /* for (hash) */
4044
4045 if (count == 0) /* no match found */
4046 break; /* for (round) */
4047
4048 if (round == 1)
4049 {
4050 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
4051 if (*file == NULL)
4052 return FAIL;
4053 }
4054 } /* for (round) */
4055
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004056 if (count > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004058 char_u **ptr1;
4059 char_u **ptr2;
4060 char_u **ptr3;
4061
4062 /* Sort the matches */
4063 sort_strings(*file, count);
4064
4065 /* Remove multiple entries */
4066 ptr1 = *file;
4067 ptr2 = ptr1 + 1;
4068 ptr3 = ptr1 + count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069
4070 while (ptr2 < ptr3)
4071 {
4072 if (STRCMP(*ptr1, *ptr2))
4073 *++ptr1 = *ptr2++;
4074 else
4075 {
4076 vim_free(*ptr2++);
4077 count--;
4078 }
4079 }
4080 }
4081
4082 *num_file = count;
4083 return (count == 0 ? FAIL : OK);
4084}
4085#endif /* FEAT_CMDL_COMPL */
4086
4087/*
4088 * Check for an abbreviation.
4089 * Cursor is at ptr[col]. When inserting, mincol is where insert started.
4090 * "c" is the character typed before check_abbr was called. It may have
4091 * ABBR_OFF added to avoid prepending a CTRL-V to it.
4092 *
4093 * Historic vi practice: The last character of an abbreviation must be an id
4094 * character ([a-zA-Z0-9_]). The characters in front of it must be all id
4095 * characters or all non-id characters. This allows for abbr. "#i" to
4096 * "#include".
4097 *
4098 * Vim addition: Allow for abbreviations that end in a non-keyword character.
4099 * Then there must be white space before the abbr.
4100 *
4101 * return TRUE if there is an abbreviation, FALSE if not
4102 */
4103 int
4104check_abbr(c, ptr, col, mincol)
4105 int c;
4106 char_u *ptr;
4107 int col;
4108 int mincol;
4109{
4110 int len;
4111 int scol; /* starting column of the abbr. */
4112 int j;
Bram Moolenaar4e427192006-03-10 21:34:27 +00004113 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114#ifdef FEAT_MBYTE
4115 char_u tb[MB_MAXBYTES + 4];
4116#else
4117 char_u tb[4];
4118#endif
4119 mapblock_T *mp;
4120#ifdef FEAT_LOCALMAP
4121 mapblock_T *mp2;
4122#endif
4123#ifdef FEAT_MBYTE
4124 int clen = 0; /* length in characters */
4125#endif
4126 int is_id = TRUE;
4127 int vim_abbr;
4128
4129 if (typebuf.tb_no_abbr_cnt) /* abbrev. are not recursive */
4130 return FALSE;
4131 if (KeyNoremap) /* no remapping implies no abbreviation */
4132 return FALSE;
4133
4134 /*
4135 * Check for word before the cursor: If it ends in a keyword char all
4136 * chars before it must be al keyword chars or non-keyword chars, but not
4137 * white space. If it ends in a non-keyword char we accept any characters
4138 * before it except white space.
4139 */
4140 if (col == 0) /* cannot be an abbr. */
4141 return FALSE;
4142
4143#ifdef FEAT_MBYTE
4144 if (has_mbyte)
4145 {
4146 char_u *p;
4147
4148 p = mb_prevptr(ptr, ptr + col);
4149 if (!vim_iswordp(p))
4150 vim_abbr = TRUE; /* Vim added abbr. */
4151 else
4152 {
4153 vim_abbr = FALSE; /* vi compatible abbr. */
4154 if (p > ptr)
4155 is_id = vim_iswordp(mb_prevptr(ptr, p));
4156 }
4157 clen = 1;
4158 while (p > ptr + mincol)
4159 {
4160 p = mb_prevptr(ptr, p);
4161 if (vim_isspace(*p) || (!vim_abbr && is_id != vim_iswordp(p)))
4162 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004163 p += (*mb_ptr2len)(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164 break;
4165 }
4166 ++clen;
4167 }
4168 scol = (int)(p - ptr);
4169 }
4170 else
4171#endif
4172 {
4173 if (!vim_iswordc(ptr[col - 1]))
4174 vim_abbr = TRUE; /* Vim added abbr. */
4175 else
4176 {
4177 vim_abbr = FALSE; /* vi compatible abbr. */
4178 if (col > 1)
4179 is_id = vim_iswordc(ptr[col - 2]);
4180 }
4181 for (scol = col - 1; scol > 0 && !vim_isspace(ptr[scol - 1])
4182 && (vim_abbr || is_id == vim_iswordc(ptr[scol - 1])); --scol)
4183 ;
4184 }
4185
4186 if (scol < mincol)
4187 scol = mincol;
4188 if (scol < col) /* there is a word in front of the cursor */
4189 {
4190 ptr += scol;
4191 len = col - scol;
4192#ifdef FEAT_LOCALMAP
4193 mp = curbuf->b_first_abbr;
4194 mp2 = first_abbr;
4195 if (mp == NULL)
4196 {
4197 mp = mp2;
4198 mp2 = NULL;
4199 }
4200#else
4201 mp = first_abbr;
4202#endif
4203 for ( ; mp;
4204#ifdef FEAT_LOCALMAP
4205 mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
4206#endif
4207 (mp = mp->m_next))
4208 {
4209 /* find entries with right mode and keys */
4210 if ( (mp->m_mode & State)
4211 && mp->m_keylen == len
4212 && !STRNCMP(mp->m_keys, ptr, (size_t)len))
4213 break;
4214 }
4215 if (mp != NULL)
4216 {
4217 /*
4218 * Found a match:
4219 * Insert the rest of the abbreviation in typebuf.tb_buf[].
4220 * This goes from end to start.
4221 *
4222 * Characters 0x000 - 0x100: normal chars, may need CTRL-V,
4223 * except K_SPECIAL: Becomes K_SPECIAL KS_SPECIAL KE_FILLER
4224 * Characters where IS_SPECIAL() == TRUE: key codes, need
4225 * K_SPECIAL. Other characters (with ABBR_OFF): don't use CTRL-V.
4226 *
4227 * Character CTRL-] is treated specially - it completes the
4228 * abbreviation, but is not inserted into the input stream.
4229 */
4230 j = 0;
4231 /* special key code, split up */
4232 if (c != Ctrl_RSB)
4233 {
4234 if (IS_SPECIAL(c) || c == K_SPECIAL)
4235 {
4236 tb[j++] = K_SPECIAL;
4237 tb[j++] = K_SECOND(c);
4238 tb[j++] = K_THIRD(c);
4239 }
4240 else
4241 {
4242 if (c < ABBR_OFF && (c < ' ' || c > '~'))
4243 tb[j++] = Ctrl_V; /* special char needs CTRL-V */
4244#ifdef FEAT_MBYTE
4245 if (has_mbyte)
4246 {
4247 /* if ABBR_OFF has been added, remove it here */
4248 if (c >= ABBR_OFF)
4249 c -= ABBR_OFF;
4250 j += (*mb_char2bytes)(c, tb + j);
4251 }
4252 else
4253#endif
4254 tb[j++] = c;
4255 }
4256 tb[j] = NUL;
4257 /* insert the last typed char */
4258 (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
4259 }
Bram Moolenaar4e427192006-03-10 21:34:27 +00004260#ifdef FEAT_EVAL
4261 if (mp->m_expr)
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004262 s = eval_map_expr(mp->m_str);
Bram Moolenaar4e427192006-03-10 21:34:27 +00004263 else
4264#endif
4265 s = mp->m_str;
4266 if (s != NULL)
4267 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 /* insert the to string */
Bram Moolenaar4e427192006-03-10 21:34:27 +00004269 (void)ins_typebuf(s, mp->m_noremap, 0, TRUE, mp->m_silent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 /* no abbrev. for these chars */
Bram Moolenaar4e427192006-03-10 21:34:27 +00004271 typebuf.tb_no_abbr_cnt += (int)STRLEN(s) + j + 1;
4272#ifdef FEAT_EVAL
4273 if (mp->m_expr)
4274 vim_free(s);
4275#endif
4276 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277
4278 tb[0] = Ctrl_H;
4279 tb[1] = NUL;
4280#ifdef FEAT_MBYTE
4281 if (has_mbyte)
4282 len = clen; /* Delete characters instead of bytes */
4283#endif
4284 while (len-- > 0) /* delete the from string */
4285 (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
4286 return TRUE;
4287 }
4288 }
4289 return FALSE;
4290}
4291
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004292#ifdef FEAT_EVAL
4293/*
4294 * Evaluate the RHS of a mapping or abbreviations and take care of escaping
4295 * special characters.
4296 */
4297 static char_u *
4298eval_map_expr(str)
4299 char_u *str;
4300{
4301 char_u *res;
Bram Moolenaar8424a622006-04-19 21:23:36 +00004302 char_u *p;
4303 char_u *s, *d;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004304
Bram Moolenaar8424a622006-04-19 21:23:36 +00004305 p = eval_to_string(str, NULL, FALSE);
4306 if (p == NULL)
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004307 return NULL;
4308
4309 /* Need a buffer to hold up to three times as much. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00004310 res = alloc((unsigned)(STRLEN(p) * 3) + 1);
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004311 if (res != NULL)
4312 {
Bram Moolenaar8424a622006-04-19 21:23:36 +00004313 d = res;
4314 for (s = p; *s != NUL; )
4315 {
4316 if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL)
4317 {
4318 /* Copy special key unmodified. */
4319 *d++ = *s++;
4320 *d++ = *s++;
4321 *d++ = *s++;
4322 }
4323 else
4324 {
4325 /* Add character, possibly multi-byte to destination, escaping
4326 * CSI and K_SPECIAL. */
4327 d = add_char2buf(PTR2CHAR(s), d);
4328 mb_ptr_adv(s);
4329 }
4330 }
4331 *d = NUL;
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004332 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00004333
4334 vim_free(p);
4335
Bram Moolenaarc1e37902006-04-18 21:55:01 +00004336 return res;
4337}
4338#endif
4339
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340/*
4341 * Write map commands for the current mappings to an .exrc file.
4342 * Return FAIL on error, OK otherwise.
4343 */
4344 int
4345makemap(fd, buf)
4346 FILE *fd;
4347 buf_T *buf; /* buffer for local mappings or NULL */
4348{
4349 mapblock_T *mp;
4350 char_u c1, c2;
4351 char_u *p;
4352 char *cmd;
4353 int abbr;
4354 int hash;
4355 int did_cpo = FALSE;
4356 int i;
4357
4358 validate_maphash();
4359
4360 /*
4361 * Do the loop twice: Once for mappings, once for abbreviations.
4362 * Then loop over all map hash lists.
4363 */
4364 for (abbr = 0; abbr < 2; ++abbr)
4365 for (hash = 0; hash < 256; ++hash)
4366 {
4367 if (abbr)
4368 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004369 if (hash > 0) /* there is only one abbr list */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 break;
4371#ifdef FEAT_LOCALMAP
4372 if (buf != NULL)
4373 mp = buf->b_first_abbr;
4374 else
4375#endif
4376 mp = first_abbr;
4377 }
4378 else
4379 {
4380#ifdef FEAT_LOCALMAP
4381 if (buf != NULL)
4382 mp = buf->b_maphash[hash];
4383 else
4384#endif
4385 mp = maphash[hash];
4386 }
4387
4388 for ( ; mp; mp = mp->m_next)
4389 {
4390 /* skip script-local mappings */
4391 if (mp->m_noremap == REMAP_SCRIPT)
4392 continue;
4393
4394 /* skip mappings that contain a <SNR> (script-local thing),
4395 * they probably don't work when loaded again */
4396 for (p = mp->m_str; *p != NUL; ++p)
4397 if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
4398 && p[2] == (int)KE_SNR)
4399 break;
4400 if (*p != NUL)
4401 continue;
4402
4403 c1 = NUL;
4404 c2 = NUL;
4405 if (abbr)
4406 cmd = "abbr";
4407 else
4408 cmd = "map";
4409 switch (mp->m_mode)
4410 {
Bram Moolenaar371d5402006-03-20 21:47:49 +00004411 case NORMAL + VISUAL + SELECTMODE + OP_PENDING:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 break;
4413 case NORMAL:
4414 c1 = 'n';
4415 break;
Bram Moolenaar371d5402006-03-20 21:47:49 +00004416 case VISUAL + SELECTMODE:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417 c1 = 'v';
4418 break;
Bram Moolenaar371d5402006-03-20 21:47:49 +00004419 case VISUAL:
4420 c1 = 'x';
4421 break;
4422 case SELECTMODE:
4423 c1 = 's';
4424 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425 case OP_PENDING:
4426 c1 = 'o';
4427 break;
Bram Moolenaar371d5402006-03-20 21:47:49 +00004428 case NORMAL + VISUAL + SELECTMODE:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 c1 = 'n';
4430 c2 = 'v';
4431 break;
Bram Moolenaar371d5402006-03-20 21:47:49 +00004432 case VISUAL + SELECTMODE + OP_PENDING:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 c1 = 'v';
4434 c2 = 'o';
4435 break;
4436 case NORMAL + OP_PENDING:
4437 c1 = 'n';
4438 c2 = 'o';
4439 break;
4440 case CMDLINE + INSERT:
4441 if (!abbr)
4442 cmd = "map!";
4443 break;
4444 case CMDLINE:
4445 c1 = 'c';
4446 break;
4447 case INSERT:
4448 c1 = 'i';
4449 break;
4450 case LANGMAP:
4451 c1 = 'l';
4452 break;
4453 default:
4454 EMSG(_("E228: makemap: Illegal mode"));
4455 return FAIL;
4456 }
4457 do /* may do this twice if c2 is set */
4458 {
4459 /* When outputting <> form, need to make sure that 'cpo'
4460 * is set to the Vim default. */
4461 if (!did_cpo)
4462 {
4463 if (*mp->m_str == NUL) /* will use <Nop> */
4464 did_cpo = TRUE;
4465 else
4466 for (i = 0; i < 2; ++i)
4467 for (p = (i ? mp->m_str : mp->m_keys); *p; ++p)
4468 if (*p == K_SPECIAL || *p == NL)
4469 did_cpo = TRUE;
4470 if (did_cpo)
4471 {
4472 if (fprintf(fd, "let s:cpo_save=&cpo") < 0
4473 || put_eol(fd) < 0
4474 || fprintf(fd, "set cpo&vim") < 0
4475 || put_eol(fd) < 0)
4476 return FAIL;
4477 }
4478 }
4479 if (c1 && putc(c1, fd) < 0)
4480 return FAIL;
4481 if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0)
4482 return FAIL;
4483 if (fprintf(fd, cmd) < 0)
4484 return FAIL;
4485 if (buf != NULL && fputs(" <buffer>", fd) < 0)
4486 return FAIL;
4487 if (mp->m_silent && fputs(" <silent>", fd) < 0)
4488 return FAIL;
Bram Moolenaar4e427192006-03-10 21:34:27 +00004489#ifdef FEAT_EVAL
4490 if (mp->m_noremap == REMAP_SCRIPT
4491 && fputs("<script>", fd) < 0)
4492 return FAIL;
4493 if (mp->m_expr && fputs(" <expr>", fd) < 0)
4494 return FAIL;
4495#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496
4497 if ( putc(' ', fd) < 0
4498 || put_escstr(fd, mp->m_keys, 0) == FAIL
4499 || putc(' ', fd) < 0
4500 || put_escstr(fd, mp->m_str, 1) == FAIL
4501 || put_eol(fd) < 0)
4502 return FAIL;
4503 c1 = c2;
4504 c2 = NUL;
4505 }
4506 while (c1);
4507 }
4508 }
4509
4510 if (did_cpo)
4511 if (fprintf(fd, "let &cpo=s:cpo_save") < 0
4512 || put_eol(fd) < 0
4513 || fprintf(fd, "unlet s:cpo_save") < 0
4514 || put_eol(fd) < 0)
4515 return FAIL;
4516 return OK;
4517}
4518
4519/*
4520 * write escape string to file
4521 * "what": 0 for :map lhs, 1 for :map rhs, 2 for :set
4522 *
4523 * return FAIL for failure, OK otherwise
4524 */
4525 int
4526put_escstr(fd, strstart, what)
4527 FILE *fd;
4528 char_u *strstart;
4529 int what;
4530{
4531 char_u *str = strstart;
4532 int c;
4533 int modifiers;
4534
4535 /* :map xx <Nop> */
4536 if (*str == NUL && what == 1)
4537 {
4538 if (fprintf(fd, "<Nop>") < 0)
4539 return FAIL;
4540 return OK;
4541 }
4542
4543 for ( ; *str != NUL; ++str)
4544 {
4545#ifdef FEAT_MBYTE
4546 char_u *p;
4547
4548 /* Check for a multi-byte character, which may contain escaped
4549 * K_SPECIAL and CSI bytes */
4550 p = mb_unescape(&str);
4551 if (p != NULL)
4552 {
4553 while (*p != NUL)
Bram Moolenaar51485f02005-06-04 21:55:20 +00004554 if (fputc(*p++, fd) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555 return FAIL;
4556 --str;
4557 continue;
4558 }
4559#endif
4560
4561 c = *str;
4562 /*
4563 * Special key codes have to be translated to be able to make sense
4564 * when they are read back.
4565 */
4566 if (c == K_SPECIAL && what != 2)
4567 {
4568 modifiers = 0x0;
4569 if (str[1] == KS_MODIFIER)
4570 {
4571 modifiers = str[2];
4572 str += 3;
4573 c = *str;
4574 }
4575 if (c == K_SPECIAL)
4576 {
4577 c = TO_SPECIAL(str[1], str[2]);
4578 str += 2;
4579 }
4580 if (IS_SPECIAL(c) || modifiers) /* special key */
4581 {
4582 if (fprintf(fd, (char *)get_special_key_name(c, modifiers)) < 0)
4583 return FAIL;
4584 continue;
4585 }
4586 }
4587
4588 /*
4589 * A '\n' in a map command should be written as <NL>.
4590 * A '\n' in a set command should be written as \^V^J.
4591 */
4592 if (c == NL)
4593 {
4594 if (what == 2)
4595 {
4596 if (fprintf(fd, IF_EB("\\\026\n", "\\" CTRL_V_STR "\n")) < 0)
4597 return FAIL;
4598 }
4599 else
4600 {
4601 if (fprintf(fd, "<NL>") < 0)
4602 return FAIL;
4603 }
4604 continue;
4605 }
4606
4607 /*
4608 * Some characters have to be escaped with CTRL-V to
4609 * prevent them from misinterpreted in DoOneCmd().
4610 * A space, Tab and '"' has to be escaped with a backslash to
4611 * prevent it to be misinterpreted in do_set().
4612 * A space has to be escaped with a CTRL-V when it's at the start of a
4613 * ":map" rhs.
4614 * A '<' has to be escaped with a CTRL-V to prevent it being
4615 * interpreted as the start of a special key name.
4616 * A space in the lhs of a :map needs a CTRL-V.
4617 */
4618 if (what == 2 && (vim_iswhite(c) || c == '"' || c == '\\'))
4619 {
4620 if (putc('\\', fd) < 0)
4621 return FAIL;
4622 }
4623 else if (c < ' ' || c > '~' || c == '|'
4624 || (what == 0 && c == ' ')
4625 || (what == 1 && str == strstart && c == ' ')
4626 || (what != 2 && c == '<'))
4627 {
4628 if (putc(Ctrl_V, fd) < 0)
4629 return FAIL;
4630 }
4631 if (putc(c, fd) < 0)
4632 return FAIL;
4633 }
4634 return OK;
4635}
4636
4637/*
4638 * Check all mappings for the presence of special key codes.
4639 * Used after ":set term=xxx".
4640 */
4641 void
4642check_map_keycodes()
4643{
4644 mapblock_T *mp;
4645 char_u *p;
4646 int i;
4647 char_u buf[3];
4648 char_u *save_name;
4649 int abbr;
4650 int hash;
4651#ifdef FEAT_LOCALMAP
4652 buf_T *bp;
4653#endif
4654
4655 validate_maphash();
4656 save_name = sourcing_name;
4657 sourcing_name = (char_u *)"mappings"; /* avoids giving error messages */
4658
4659#ifdef FEAT_LOCALMAP
4660 /* This this once for each buffer, and then once for global
4661 * mappings/abbreviations with bp == NULL */
4662 for (bp = firstbuf; ; bp = bp->b_next)
4663 {
4664#endif
4665 /*
4666 * Do the loop twice: Once for mappings, once for abbreviations.
4667 * Then loop over all map hash lists.
4668 */
4669 for (abbr = 0; abbr <= 1; ++abbr)
4670 for (hash = 0; hash < 256; ++hash)
4671 {
4672 if (abbr)
4673 {
4674 if (hash) /* there is only one abbr list */
4675 break;
4676#ifdef FEAT_LOCALMAP
4677 if (bp != NULL)
4678 mp = bp->b_first_abbr;
4679 else
4680#endif
4681 mp = first_abbr;
4682 }
4683 else
4684 {
4685#ifdef FEAT_LOCALMAP
4686 if (bp != NULL)
4687 mp = bp->b_maphash[hash];
4688 else
4689#endif
4690 mp = maphash[hash];
4691 }
4692 for ( ; mp != NULL; mp = mp->m_next)
4693 {
4694 for (i = 0; i <= 1; ++i) /* do this twice */
4695 {
4696 if (i == 0)
4697 p = mp->m_keys; /* once for the "from" part */
4698 else
4699 p = mp->m_str; /* and once for the "to" part */
4700 while (*p)
4701 {
4702 if (*p == K_SPECIAL)
4703 {
4704 ++p;
4705 if (*p < 128) /* for "normal" tcap entries */
4706 {
4707 buf[0] = p[0];
4708 buf[1] = p[1];
4709 buf[2] = NUL;
4710 (void)add_termcap_entry(buf, FALSE);
4711 }
4712 ++p;
4713 }
4714 ++p;
4715 }
4716 }
4717 }
4718 }
4719#ifdef FEAT_LOCALMAP
4720 if (bp == NULL)
4721 break;
4722 }
4723#endif
4724 sourcing_name = save_name;
4725}
4726
4727#ifdef FEAT_EVAL
4728/*
4729 * Check the string "keys" against the lhs of all mappings
4730 * Return pointer to rhs of mapping (mapblock->m_str)
4731 * NULL otherwise
4732 */
4733 char_u *
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004734check_map(keys, mode, exact, ign_mod, abbr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 char_u *keys;
4736 int mode;
4737 int exact; /* require exact match */
Bram Moolenaar686f51e2005-05-20 21:19:57 +00004738 int ign_mod; /* ignore preceding modifier */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004739 int abbr; /* do abbreviations */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740{
4741 int hash;
4742 int len, minlen;
4743 mapblock_T *mp;
Bram Moolenaar686f51e2005-05-20 21:19:57 +00004744 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745#ifdef FEAT_LOCALMAP
4746 int local;
4747#endif
4748
4749 validate_maphash();
4750
4751 len = (int)STRLEN(keys);
4752#ifdef FEAT_LOCALMAP
4753 for (local = 1; local >= 0; --local)
4754#endif
4755 /* loop over all hash lists */
4756 for (hash = 0; hash < 256; ++hash)
4757 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004758 if (abbr)
4759 {
4760 if (hash > 0) /* there is only one list. */
4761 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762#ifdef FEAT_LOCALMAP
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004763 if (local)
4764 mp = curbuf->b_first_abbr;
4765 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766#endif
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004767 mp = first_abbr;
4768 }
4769#ifdef FEAT_LOCALMAP
4770 else if (local)
4771 mp = curbuf->b_maphash[hash];
4772#endif
4773 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774 mp = maphash[hash];
4775 for ( ; mp != NULL; mp = mp->m_next)
4776 {
4777 /* skip entries with wrong mode, wrong length and not matching
4778 * ones */
Bram Moolenaar686f51e2005-05-20 21:19:57 +00004779 if ((mp->m_mode & mode) && (!exact || mp->m_keylen == len))
4780 {
4781 if (len > mp->m_keylen)
4782 minlen = mp->m_keylen;
4783 else
4784 minlen = len;
4785 s = mp->m_keys;
4786 if (ign_mod && s[0] == K_SPECIAL && s[1] == KS_MODIFIER
4787 && s[2] != NUL)
4788 {
4789 s += 3;
4790 if (len > mp->m_keylen - 3)
4791 minlen = mp->m_keylen - 3;
4792 }
4793 if (STRNCMP(s, keys, minlen) == 0)
4794 return mp->m_str;
4795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796 }
4797 }
4798
4799 return NULL;
4800}
4801#endif
4802
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004803#if defined(MSDOS) || defined(MSWIN) || defined(OS2) || defined(MACOS)
Bram Moolenaar371d5402006-03-20 21:47:49 +00004804
4805#define VIS_SEL (VISUAL+SELECTMODE) /* abbreviation */
4806
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807/*
4808 * Default mappings for some often used keys.
4809 */
4810static struct initmap
4811{
4812 char_u *arg;
4813 int mode;
4814} initmappings[] =
4815{
4816#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
4817 /* Use the Windows (CUA) keybindings. */
4818# ifdef FEAT_GUI
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004819# if 0 /* These are now used to move tab pages */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004820 {(char_u *)"<C-PageUp> H", NORMAL+VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 {(char_u *)"<C-PageUp> <C-O>H",INSERT},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004822 {(char_u *)"<C-PageDown> L$", NORMAL+VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 {(char_u *)"<C-PageDown> <C-O>L<C-O>$", INSERT},
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004824# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825
4826 /* paste, copy and cut */
4827 {(char_u *)"<S-Insert> \"*P", NORMAL},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004828 {(char_u *)"<S-Insert> \"-d\"*P", VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829 {(char_u *)"<S-Insert> <C-R><C-O>*", INSERT+CMDLINE},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004830 {(char_u *)"<C-Insert> \"*y", VIS_SEL},
4831 {(char_u *)"<S-Del> \"*d", VIS_SEL},
4832 {(char_u *)"<C-Del> \"*d", VIS_SEL},
4833 {(char_u *)"<C-X> \"*d", VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004834 /* Missing: CTRL-C (cancel) and CTRL-V (block selection) */
4835# else
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004836# if 0 /* These are now used to move tab pages */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004837 {(char_u *)"\316\204 H", NORMAL+VIS_SEL}, /* CTRL-PageUp is "H" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 {(char_u *)"\316\204 \017H",INSERT}, /* CTRL-PageUp is "^OH"*/
Bram Moolenaar371d5402006-03-20 21:47:49 +00004839 {(char_u *)"\316v L$", NORMAL+VIS_SEL}, /* CTRL-PageDown is "L$" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840 {(char_u *)"\316v \017L\017$", INSERT}, /* CTRL-PageDown ="^OL^O$"*/
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004841# endif
Bram Moolenaar371d5402006-03-20 21:47:49 +00004842 {(char_u *)"\316w <C-Home>", NORMAL+VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 {(char_u *)"\316w <C-Home>", INSERT+CMDLINE},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004844 {(char_u *)"\316u <C-End>", NORMAL+VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004845 {(char_u *)"\316u <C-End>", INSERT+CMDLINE},
4846
4847 /* paste, copy and cut */
4848# ifdef FEAT_CLIPBOARD
4849# ifdef DJGPP
4850 {(char_u *)"\316\122 \"*P", NORMAL}, /* SHIFT-Insert is "*P */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004851 {(char_u *)"\316\122 \"-d\"*P", VIS_SEL}, /* SHIFT-Insert is "-d"*P */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852 {(char_u *)"\316\122 \022\017*", INSERT}, /* SHIFT-Insert is ^R^O* */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004853 {(char_u *)"\316\222 \"*y", VIS_SEL}, /* CTRL-Insert is "*y */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004854# if 0 /* Shift-Del produces the same code as Del */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004855 {(char_u *)"\316\123 \"*d", VIS_SEL}, /* SHIFT-Del is "*d */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856# endif
Bram Moolenaar371d5402006-03-20 21:47:49 +00004857 {(char_u *)"\316\223 \"*d", VIS_SEL}, /* CTRL-Del is "*d */
4858 {(char_u *)"\030 \"-d", VIS_SEL}, /* CTRL-X is "-d */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004859# else
4860 {(char_u *)"\316\324 \"*P", NORMAL}, /* SHIFT-Insert is "*P */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004861 {(char_u *)"\316\324 \"-d\"*P", VIS_SEL}, /* SHIFT-Insert is "-d"*P */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 {(char_u *)"\316\324 \022\017*", INSERT}, /* SHIFT-Insert is ^R^O* */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004863 {(char_u *)"\316\325 \"*y", VIS_SEL}, /* CTRL-Insert is "*y */
4864 {(char_u *)"\316\327 \"*d", VIS_SEL}, /* SHIFT-Del is "*d */
4865 {(char_u *)"\316\330 \"*d", VIS_SEL}, /* CTRL-Del is "*d */
4866 {(char_u *)"\030 \"-d", VIS_SEL}, /* CTRL-X is "-d */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867# endif
4868# else
4869 {(char_u *)"\316\324 P", NORMAL}, /* SHIFT-Insert is P */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004870 {(char_u *)"\316\324 \"-dP", VIS_SEL}, /* SHIFT-Insert is "-dP */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 {(char_u *)"\316\324 \022\017\"", INSERT}, /* SHIFT-Insert is ^R^O" */
Bram Moolenaar371d5402006-03-20 21:47:49 +00004872 {(char_u *)"\316\325 y", VIS_SEL}, /* CTRL-Insert is y */
4873 {(char_u *)"\316\327 d", VIS_SEL}, /* SHIFT-Del is d */
4874 {(char_u *)"\316\330 d", VIS_SEL}, /* CTRL-Del is d */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875# endif
4876# endif
4877#endif
4878
4879#if defined(MACOS)
4880 /* Use the Standard MacOS binding. */
4881 /* paste, copy and cut */
4882 {(char_u *)"<D-v> \"*P", NORMAL},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004883 {(char_u *)"<D-v> \"-d\"*P", VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 {(char_u *)"<D-v> <C-R>*", INSERT+CMDLINE},
Bram Moolenaar371d5402006-03-20 21:47:49 +00004885 {(char_u *)"<D-c> \"*y", VIS_SEL},
4886 {(char_u *)"<D-x> \"*d", VIS_SEL},
4887 {(char_u *)"<Backspace> \"-d", VIS_SEL},
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889};
Bram Moolenaar371d5402006-03-20 21:47:49 +00004890
4891# undef VIS_SEL
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004892#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004893
4894/*
4895 * Set up default mappings.
4896 */
4897 void
4898init_mappings()
4899{
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004900#if defined(MSDOS) || defined(MSWIN) || defined(OS2) || defined(MACOS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 int i;
4902
4903 for (i = 0; i < sizeof(initmappings) / sizeof(struct initmap); ++i)
4904 add_map(initmappings[i].arg, initmappings[i].mode);
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004905#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906}
4907
Bram Moolenaar52b4b552005-03-07 23:00:57 +00004908#if defined(MSDOS) || defined(MSWIN) || defined(OS2) \
4909 || defined(FEAT_CMDWIN) || defined(MACOS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910/*
4911 * Add a mapping "map" for mode "mode".
4912 * Need to put string in allocated memory, because do_map() will modify it.
4913 */
4914 void
4915add_map(map, mode)
4916 char_u *map;
4917 int mode;
4918{
4919 char_u *s;
4920 char_u *cpo_save = p_cpo;
4921
4922 p_cpo = (char_u *)""; /* Allow <> notation */
4923 s = vim_strsave(map);
4924 if (s != NULL)
4925 {
4926 (void)do_map(0, s, mode, FALSE);
4927 vim_free(s);
4928 }
4929 p_cpo = cpo_save;
4930}
Bram Moolenaar52b4b552005-03-07 23:00:57 +00004931#endif