xref: /vim-8.2.3635/src/normal.c (revision c0197e28)
1 /* 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  * normal.c:	Contains the main routine for processing characters in command
11  *		mode.  Communicates closely with the code in ops.c to handle
12  *		the operators.
13  */
14 
15 #include "vim.h"
16 
17 #ifdef FEAT_VISUAL
18 /*
19  * The Visual area is remembered for reselection.
20  */
21 static int	resel_VIsual_mode = NUL;	/* 'v', 'V', or Ctrl-V */
22 static linenr_T	resel_VIsual_line_count;	/* number of lines */
23 static colnr_T	resel_VIsual_col;		/* nr of cols or end col */
24 
25 static int	restart_VIsual_select = 0;
26 #endif
27 
28 static int
29 # ifdef __BORLANDC__
30 _RTLENTRYF
31 # endif
32 		nv_compare __ARGS((const void *s1, const void *s2));
33 static int	find_command __ARGS((int cmdchar));
34 static void	op_colon __ARGS((oparg_T *oap));
35 #if defined(FEAT_MOUSE) && defined(FEAT_VISUAL)
36 static void	find_start_of_word __ARGS((pos_T *));
37 static void	find_end_of_word __ARGS((pos_T *));
38 static int	get_mouse_class __ARGS((char_u *p));
39 #endif
40 static void	prep_redo_cmd __ARGS((cmdarg_T *cap));
41 static void	prep_redo __ARGS((int regname, long, int, int, int, int, int));
42 static int	checkclearop __ARGS((oparg_T *oap));
43 static int	checkclearopq __ARGS((oparg_T *oap));
44 static void	clearop __ARGS((oparg_T *oap));
45 static void	clearopbeep __ARGS((oparg_T *oap));
46 #ifdef FEAT_VISUAL
47 static void	unshift_special __ARGS((cmdarg_T *cap));
48 #endif
49 #ifdef FEAT_CMDL_INFO
50 static void	del_from_showcmd __ARGS((int));
51 #endif
52 
53 /*
54  * nv_*(): functions called to handle Normal and Visual mode commands.
55  * n_*(): functions called to handle Normal mode commands.
56  * v_*(): functions called to handle Visual mode commands.
57  */
58 static void	nv_ignore __ARGS((cmdarg_T *cap));
59 static void	nv_error __ARGS((cmdarg_T *cap));
60 static void	nv_help __ARGS((cmdarg_T *cap));
61 static void	nv_addsub __ARGS((cmdarg_T *cap));
62 static void	nv_page __ARGS((cmdarg_T *cap));
63 static void	nv_gd __ARGS((oparg_T *oap, int nchar));
64 static int	nv_screengo __ARGS((oparg_T *oap, int dir, long dist));
65 #ifdef FEAT_MOUSE
66 static void	nv_mousescroll __ARGS((cmdarg_T *cap));
67 static void	nv_mouse __ARGS((cmdarg_T *cap));
68 #endif
69 static void	nv_scroll_line __ARGS((cmdarg_T *cap));
70 static void	nv_zet __ARGS((cmdarg_T *cap));
71 #ifdef FEAT_GUI
72 static void	nv_ver_scrollbar __ARGS((cmdarg_T *cap));
73 static void	nv_hor_scrollbar __ARGS((cmdarg_T *cap));
74 #endif
75 static void	nv_exmode __ARGS((cmdarg_T *cap));
76 static void	nv_colon __ARGS((cmdarg_T *cap));
77 static void	nv_ctrlg __ARGS((cmdarg_T *cap));
78 static void	nv_ctrlh __ARGS((cmdarg_T *cap));
79 static void	nv_clear __ARGS((cmdarg_T *cap));
80 static void	nv_ctrlo __ARGS((cmdarg_T *cap));
81 static void	nv_hat __ARGS((cmdarg_T *cap));
82 static void	nv_Zet __ARGS((cmdarg_T *cap));
83 static void	nv_ident __ARGS((cmdarg_T *cap));
84 #ifdef FEAT_VISUAL
85 static int	get_visual_text __ARGS((cmdarg_T *cap, char_u **pp, int *lenp));
86 #endif
87 static void	nv_tagpop __ARGS((cmdarg_T *cap));
88 static void	nv_scroll __ARGS((cmdarg_T *cap));
89 static void	nv_right __ARGS((cmdarg_T *cap));
90 static void	nv_left __ARGS((cmdarg_T *cap));
91 static void	nv_up __ARGS((cmdarg_T *cap));
92 static void	nv_down __ARGS((cmdarg_T *cap));
93 #ifdef FEAT_SEARCHPATH
94 static void	nv_gotofile __ARGS((cmdarg_T *cap));
95 #endif
96 static void	nv_end __ARGS((cmdarg_T *cap));
97 static void	nv_dollar __ARGS((cmdarg_T *cap));
98 static void	nv_search __ARGS((cmdarg_T *cap));
99 static void	nv_next __ARGS((cmdarg_T *cap));
100 static void	normal_search __ARGS((cmdarg_T *cap, int dir, char_u *pat, int opt));
101 static void	nv_csearch __ARGS((cmdarg_T *cap));
102 static void	nv_brackets __ARGS((cmdarg_T *cap));
103 static void	nv_percent __ARGS((cmdarg_T *cap));
104 static void	nv_brace __ARGS((cmdarg_T *cap));
105 static void	nv_mark __ARGS((cmdarg_T *cap));
106 static void	nv_findpar __ARGS((cmdarg_T *cap));
107 static void	nv_undo __ARGS((cmdarg_T *cap));
108 static void	nv_kundo __ARGS((cmdarg_T *cap));
109 static void	nv_Replace __ARGS((cmdarg_T *cap));
110 #ifdef FEAT_VREPLACE
111 static void	nv_vreplace __ARGS((cmdarg_T *cap));
112 #endif
113 #ifdef FEAT_VISUAL
114 static void	v_swap_corners __ARGS((int cmdchar));
115 #endif
116 static void	nv_replace __ARGS((cmdarg_T *cap));
117 static void	n_swapchar __ARGS((cmdarg_T *cap));
118 static void	nv_cursormark __ARGS((cmdarg_T *cap, int flag, pos_T *pos));
119 #ifdef FEAT_VISUAL
120 static void	v_visop __ARGS((cmdarg_T *cap));
121 #endif
122 static void	nv_subst __ARGS((cmdarg_T *cap));
123 static void	nv_abbrev __ARGS((cmdarg_T *cap));
124 static void	nv_optrans __ARGS((cmdarg_T *cap));
125 static void	nv_gomark __ARGS((cmdarg_T *cap));
126 static void	nv_pcmark __ARGS((cmdarg_T *cap));
127 static void	nv_regname __ARGS((cmdarg_T *cap));
128 #ifdef FEAT_VISUAL
129 static void	nv_visual __ARGS((cmdarg_T *cap));
130 static void	n_start_visual_mode __ARGS((int c));
131 #endif
132 static void	nv_window __ARGS((cmdarg_T *cap));
133 static void	nv_suspend __ARGS((cmdarg_T *cap));
134 static void	nv_g_cmd __ARGS((cmdarg_T *cap));
135 static void	n_opencmd __ARGS((cmdarg_T *cap));
136 static void	nv_dot __ARGS((cmdarg_T *cap));
137 static void	nv_redo __ARGS((cmdarg_T *cap));
138 static void	nv_Undo __ARGS((cmdarg_T *cap));
139 static void	nv_tilde __ARGS((cmdarg_T *cap));
140 static void	nv_operator __ARGS((cmdarg_T *cap));
141 static void	nv_lineop __ARGS((cmdarg_T *cap));
142 static void	nv_home __ARGS((cmdarg_T *cap));
143 static void	nv_pipe __ARGS((cmdarg_T *cap));
144 static void	nv_bck_word __ARGS((cmdarg_T *cap));
145 static void	nv_wordcmd __ARGS((cmdarg_T *cap));
146 static void	nv_beginline __ARGS((cmdarg_T *cap));
147 #ifdef FEAT_VISUAL
148 static void	adjust_for_sel __ARGS((cmdarg_T *cap));
149 static int	unadjust_for_sel __ARGS((void));
150 static void	nv_select __ARGS((cmdarg_T *cap));
151 #endif
152 static void	nv_goto __ARGS((cmdarg_T *cap));
153 static void	nv_normal __ARGS((cmdarg_T *cap));
154 static void	nv_esc __ARGS((cmdarg_T *oap));
155 static void	nv_edit __ARGS((cmdarg_T *cap));
156 static void	invoke_edit __ARGS((cmdarg_T *cap, int repl, int cmd, int startln));
157 #ifdef FEAT_TEXTOBJ
158 static void	nv_object __ARGS((cmdarg_T *cap));
159 #endif
160 static void	nv_record __ARGS((cmdarg_T *cap));
161 static void	nv_at __ARGS((cmdarg_T *cap));
162 static void	nv_halfpage __ARGS((cmdarg_T *cap));
163 static void	nv_join __ARGS((cmdarg_T *cap));
164 static void	nv_put __ARGS((cmdarg_T *cap));
165 static void	nv_open __ARGS((cmdarg_T *cap));
166 #ifdef FEAT_SNIFF
167 static void	nv_sniff __ARGS((cmdarg_T *cap));
168 #endif
169 #ifdef FEAT_NETBEANS_INTG
170 static void	nv_nbcmd __ARGS((cmdarg_T *cap));
171 #endif
172 #ifdef FEAT_DND
173 static void	nv_drop __ARGS((cmdarg_T *cap));
174 #endif
175 
176 /*
177  * Function to be called for a Normal or Visual mode command.
178  * The argument is a cmdarg_T.
179  */
180 typedef void (*nv_func_T) __ARGS((cmdarg_T *cap));
181 
182 /* Values for cmd_flags. */
183 #define NV_NCH	    0x01	  /* may need to get a second char */
184 #define NV_NCH_NOP  (0x02|NV_NCH) /* get second char when no operator pending */
185 #define NV_NCH_ALW  (0x04|NV_NCH) /* always get a second char */
186 #define NV_LANG	    0x08	/* second char needs language adjustment */
187 
188 #define NV_SS	    0x10	/* may start selection */
189 #define NV_SSS	    0x20	/* may start selection with shift modifier */
190 #define NV_STS	    0x40	/* may stop selection without shift modif. */
191 #define NV_RL	    0x80	/* 'rightleft' modifies command */
192 #define NV_KEEPREG  0x100	/* don't clear regname */
193 #define NV_NCW	    0x200	/* not allowed in command-line window */
194 
195 /*
196  * Generally speaking, every Normal mode command should either clear any
197  * pending operator (with *clearop*()), or set the motion type variable
198  * oap->motion_type.
199  *
200  * When a cursor motion command is made, it is marked as being a character or
201  * line oriented motion.  Then, if an operator is in effect, the operation
202  * becomes character or line oriented accordingly.
203  */
204 
205 /*
206  * This table contains one entry for every Normal or Visual mode command.
207  * The order doesn't matter, init_normal_cmds() will create a sorted index.
208  * It is faster when all keys from zero to '~' are present.
209  */
210 static const struct nv_cmd
211 {
212     int		cmd_char;	/* (first) command character */
213     nv_func_T   cmd_func;	/* function for this command */
214     short_u	cmd_flags;	/* NV_ flags */
215     short	cmd_arg;	/* value for ca.arg */
216 } nv_cmds[] =
217 {
218     {NUL,	nv_error,	0,			0},
219     {Ctrl_A,	nv_addsub,	0,			0},
220     {Ctrl_B,	nv_page,	NV_STS,			BACKWARD},
221     {Ctrl_C,	nv_esc,		0,			TRUE},
222     {Ctrl_D,	nv_halfpage,	0,			0},
223     {Ctrl_E,	nv_scroll_line,	0,			TRUE},
224     {Ctrl_F,	nv_page,	NV_STS,			FORWARD},
225     {Ctrl_G,	nv_ctrlg,	0,			0},
226     {Ctrl_H,	nv_ctrlh,	0,			0},
227     {Ctrl_I,	nv_pcmark,	0,			0},
228     {NL,	nv_down,	0,			FALSE},
229     {Ctrl_K,	nv_error,	0,			0},
230     {Ctrl_L,	nv_clear,	0,			0},
231     {CAR,	nv_down,	0,			TRUE},
232     {Ctrl_N,	nv_down,	NV_STS,			FALSE},
233     {Ctrl_O,	nv_ctrlo,	0,			0},
234     {Ctrl_P,	nv_up,		NV_STS,			FALSE},
235     {Ctrl_Q,	nv_ignore,	0,			0},
236     {Ctrl_R,	nv_redo,	0,			0},
237     {Ctrl_S,	nv_ignore,	0,			0},
238     {Ctrl_T,	nv_tagpop,	NV_NCW,			0},
239     {Ctrl_U,	nv_halfpage,	0,			0},
240 #ifdef FEAT_VISUAL
241     {Ctrl_V,	nv_visual,	0,			FALSE},
242     {'V',	nv_visual,	0,			FALSE},
243     {'v',	nv_visual,	0,			FALSE},
244 #else
245     {Ctrl_V,	nv_error,	0,			0},
246     {'V',	nv_error,	0,			0},
247     {'v',	nv_error,	0,			0},
248 #endif
249     {Ctrl_W,	nv_window,	0,			0},
250     {Ctrl_X,	nv_addsub,	0,			0},
251     {Ctrl_Y,	nv_scroll_line,	0,			FALSE},
252     {Ctrl_Z,	nv_suspend,	0,			0},
253     {ESC,	nv_esc,		0,			FALSE},
254     {Ctrl_BSL,	nv_normal,	NV_NCH_ALW,		0},
255     {Ctrl_RSB,	nv_ident,	NV_NCW,			0},
256     {Ctrl_HAT,	nv_hat,		NV_NCW,			0},
257     {Ctrl__,	nv_error,	0,			0},
258     {' ',	nv_right,	0,			0},
259     {'!',	nv_operator,	0,			0},
260     {'"',	nv_regname,	NV_NCH_NOP|NV_KEEPREG,	0},
261     {'#',	nv_ident,	0,			0},
262     {'$',	nv_dollar,	0,			0},
263     {'%',	nv_percent,	0,			0},
264     {'&',	nv_optrans,	0,			0},
265     {'\'',	nv_gomark,	NV_NCH_ALW,		TRUE},
266     {'(',	nv_brace,	0,			BACKWARD},
267     {')',	nv_brace,	0,			FORWARD},
268     {'*',	nv_ident,	0,			0},
269     {'+',	nv_down,	0,			TRUE},
270     {',',	nv_csearch,	0,			TRUE},
271     {'-',	nv_up,		0,			TRUE},
272     {'.',	nv_dot,		NV_KEEPREG,		0},
273     {'/',	nv_search,	0,			FALSE},
274     {'0',	nv_beginline,	0,			0},
275     {'1',	nv_ignore,	0,			0},
276     {'2',	nv_ignore,	0,			0},
277     {'3',	nv_ignore,	0,			0},
278     {'4',	nv_ignore,	0,			0},
279     {'5',	nv_ignore,	0,			0},
280     {'6',	nv_ignore,	0,			0},
281     {'7',	nv_ignore,	0,			0},
282     {'8',	nv_ignore,	0,			0},
283     {'9',	nv_ignore,	0,			0},
284     {':',	nv_colon,	0,			0},
285     {';',	nv_csearch,	0,			FALSE},
286     {'<',	nv_operator,	NV_RL,			0},
287     {'=',	nv_operator,	0,			0},
288     {'>',	nv_operator,	NV_RL,			0},
289     {'?',	nv_search,	0,			FALSE},
290     {'@',	nv_at,		NV_NCH_NOP,		FALSE},
291     {'A',	nv_edit,	0,			0},
292     {'B',	nv_bck_word,	0,			1},
293     {'C',	nv_abbrev,	NV_KEEPREG,		0},
294     {'D',	nv_abbrev,	NV_KEEPREG,		0},
295     {'E',	nv_wordcmd,	0,			TRUE},
296     {'F',	nv_csearch,	NV_NCH_ALW|NV_LANG,	BACKWARD},
297     {'G',	nv_goto,	0,			TRUE},
298     {'H',	nv_scroll,	0,			0},
299     {'I',	nv_edit,	0,			0},
300     {'J',	nv_join,	0,			0},
301     {'K',	nv_ident,	0,			0},
302     {'L',	nv_scroll,	0,			0},
303     {'M',	nv_scroll,	0,			0},
304     {'N',	nv_next,	0,			SEARCH_REV},
305     {'O',	nv_open,	0,			0},
306     {'P',	nv_put,		0,			0},
307     {'Q',	nv_exmode,	NV_NCW,			0},
308     {'R',	nv_Replace,	0,			FALSE},
309     {'S',	nv_subst,	NV_KEEPREG,		0},
310     {'T',	nv_csearch,	NV_NCH_ALW|NV_LANG,	BACKWARD},
311     {'U',	nv_Undo,	0,			0},
312     {'W',	nv_wordcmd,	0,			TRUE},
313     {'X',	nv_abbrev,	NV_KEEPREG,		0},
314     {'Y',	nv_abbrev,	NV_KEEPREG,		0},
315     {'Z',	nv_Zet,		NV_NCH_NOP|NV_NCW,	0},
316     {'[',	nv_brackets,	NV_NCH_ALW,		BACKWARD},
317     {'\\',	nv_error,	0,			0},
318     {']',	nv_brackets,	NV_NCH_ALW,		FORWARD},
319     {'^',	nv_beginline,	0,			BL_WHITE | BL_FIX},
320     {'_',	nv_lineop,	0,			0},
321     {'`',	nv_gomark,	NV_NCH_ALW,		FALSE},
322     {'a',	nv_edit,	NV_NCH,			0},
323     {'b',	nv_bck_word,	0,			0},
324     {'c',	nv_operator,	0,			0},
325     {'d',	nv_operator,	0,			0},
326     {'e',	nv_wordcmd,	0,			FALSE},
327     {'f',	nv_csearch,	NV_NCH_ALW|NV_LANG,	FORWARD},
328     {'g',	nv_g_cmd,	NV_NCH_ALW,		FALSE},
329     {'h',	nv_left,	NV_RL,			0},
330     {'i',	nv_edit,	NV_NCH,			0},
331     {'j',	nv_down,	0,			FALSE},
332     {'k',	nv_up,		0,			FALSE},
333     {'l',	nv_right,	NV_RL,			0},
334     {'m',	nv_mark,	NV_NCH_NOP,		0},
335     {'n',	nv_next,	0,			0},
336     {'o',	nv_open,	0,			0},
337     {'p',	nv_put,		0,			0},
338     {'q',	nv_record,	NV_NCH,			0},
339     {'r',	nv_replace,	NV_NCH_NOP|NV_LANG,	0},
340     {'s',	nv_subst,	NV_KEEPREG,		0},
341     {'t',	nv_csearch,	NV_NCH_ALW|NV_LANG,	FORWARD},
342     {'u',	nv_undo,	0,			0},
343     {'w',	nv_wordcmd,	0,			FALSE},
344     {'x',	nv_abbrev,	NV_KEEPREG,		0},
345     {'y',	nv_operator,	0,			0},
346     {'z',	nv_zet,		NV_NCH_ALW,		0},
347     {'{',	nv_findpar,	0,			BACKWARD},
348     {'|',	nv_pipe,	0,			0},
349     {'}',	nv_findpar,	0,			FORWARD},
350     {'~',	nv_tilde,	0,			0},
351 
352     /* pound sign */
353     {POUND,	nv_ident,	0,			0},
354 #ifdef FEAT_MOUSE
355     {K_MOUSEUP, nv_mousescroll,	0,			TRUE},
356     {K_MOUSEDOWN, nv_mousescroll, 0,			FALSE},
357     {K_LEFTMOUSE, nv_mouse,	0,			0},
358     {K_LEFTMOUSE_NM, nv_mouse,	0,			0},
359     {K_LEFTDRAG, nv_mouse,	0,			0},
360     {K_LEFTRELEASE, nv_mouse,	0,			0},
361     {K_LEFTRELEASE_NM, nv_mouse, 0,			0},
362     {K_MIDDLEMOUSE, nv_mouse,	0,			0},
363     {K_MIDDLEDRAG, nv_mouse,	0,			0},
364     {K_MIDDLERELEASE, nv_mouse,	0,			0},
365     {K_RIGHTMOUSE, nv_mouse,	0,			0},
366     {K_RIGHTDRAG, nv_mouse,	0,			0},
367     {K_RIGHTRELEASE, nv_mouse,	0,			0},
368     {K_X1MOUSE, nv_mouse,	0,			0},
369     {K_X1DRAG, nv_mouse,	0,			0},
370     {K_X1RELEASE, nv_mouse,	0,			0},
371     {K_X2MOUSE, nv_mouse,	0,			0},
372     {K_X2DRAG, nv_mouse,	0,			0},
373     {K_X2RELEASE, nv_mouse,	0,			0},
374 #endif
375     {K_IGNORE,	nv_ignore,	0,			0},
376     {K_INS,	nv_edit,	0,			0},
377     {K_KINS,	nv_edit,	0,			0},
378     {K_BS,	nv_ctrlh,	0,			0},
379     {K_UP,	nv_up,		NV_SSS|NV_STS,		FALSE},
380     {K_S_UP,	nv_page,	NV_SS,			BACKWARD},
381     {K_DOWN,	nv_down,	NV_SSS|NV_STS,		FALSE},
382     {K_S_DOWN,	nv_page,	NV_SS,			FORWARD},
383     {K_LEFT,	nv_left,	NV_SSS|NV_STS|NV_RL,	0},
384     {K_S_LEFT,	nv_bck_word,	NV_SS|NV_RL,		0},
385     {K_C_LEFT,	nv_bck_word,	NV_SSS|NV_RL|NV_STS,	1},
386     {K_RIGHT,	nv_right,	NV_SSS|NV_STS|NV_RL,	0},
387     {K_S_RIGHT,	nv_wordcmd,	NV_SS|NV_RL,		FALSE},
388     {K_C_RIGHT,	nv_wordcmd,	NV_SSS|NV_RL|NV_STS,	TRUE},
389     {K_PAGEUP,	nv_page,	NV_SSS|NV_STS,		BACKWARD},
390     {K_KPAGEUP,	nv_page,	NV_SSS|NV_STS,		BACKWARD},
391     {K_PAGEDOWN, nv_page,	NV_SSS|NV_STS,		FORWARD},
392     {K_KPAGEDOWN, nv_page,	NV_SSS|NV_STS,		FORWARD},
393     {K_END,	nv_end,		NV_SSS|NV_STS,		FALSE},
394     {K_KEND,	nv_end,		NV_SSS|NV_STS,		FALSE},
395     {K_XEND,	nv_end,		NV_SSS|NV_STS,		FALSE},
396     {K_S_END,	nv_end,		NV_SS,			FALSE},
397     {K_C_END,	nv_end,		NV_SSS|NV_STS,		TRUE},
398     {K_HOME,	nv_home,	NV_SSS|NV_STS,		0},
399     {K_KHOME,	nv_home,	NV_SSS|NV_STS,		0},
400     {K_XHOME,	nv_home,	NV_SSS|NV_STS,		0},
401     {K_S_HOME,	nv_home,	NV_SS,			0},
402     {K_C_HOME,	nv_goto,	NV_SSS|NV_STS,		FALSE},
403     {K_DEL,	nv_abbrev,	0,			0},
404     {K_KDEL,	nv_abbrev,	0,			0},
405     {K_UNDO,	nv_kundo,	0,			0},
406     {K_HELP,	nv_help,	NV_NCW,			0},
407     {K_F1,	nv_help,	NV_NCW,			0},
408     {K_XF1,	nv_help,	NV_NCW,			0},
409 #ifdef FEAT_VISUAL
410     {K_SELECT,	nv_select,	0,			0},
411 #endif
412 #ifdef FEAT_GUI
413     {K_VER_SCROLLBAR, nv_ver_scrollbar, 0,		0},
414     {K_HOR_SCROLLBAR, nv_hor_scrollbar, 0,		0},
415 #endif
416 #ifdef FEAT_FKMAP
417     {K_F8,	farsi_fkey,	0,			0},
418     {K_F9,	farsi_fkey,	0,			0},
419 #endif
420 #ifdef FEAT_SNIFF
421     {K_SNIFF,	nv_sniff,	0,			0},
422 #endif
423 #ifdef FEAT_NETBEANS_INTG
424     {K_F21,	nv_nbcmd,	NV_NCH_ALW,		0},
425 #endif
426 #ifdef FEAT_DND
427     {K_DROP,	nv_drop,	NV_STS,			0},
428 #endif
429 };
430 
431 /* Number of commands in nv_cmds[]. */
432 #define NV_CMDS_SIZE (sizeof(nv_cmds) / sizeof(struct nv_cmd))
433 
434 /* Sorted index of commands in nv_cmds[]. */
435 static short nv_cmd_idx[NV_CMDS_SIZE];
436 
437 /* The highest index for which
438  * nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char] */
439 static int nv_max_linear;
440 
441 /*
442  * Compare functions for qsort() below, that checks the command character
443  * through the index in nv_cmd_idx[].
444  */
445     static int
446 #ifdef __BORLANDC__
447 _RTLENTRYF
448 #endif
449 nv_compare(s1, s2)
450     const void	*s1;
451     const void	*s2;
452 {
453     int		c1, c2;
454 
455     /* The commands are sorted on absolute value. */
456     c1 = nv_cmds[*(const short *)s1].cmd_char;
457     c2 = nv_cmds[*(const short *)s2].cmd_char;
458     if (c1 < 0)
459 	c1 = -c1;
460     if (c2 < 0)
461 	c2 = -c2;
462     return c1 - c2;
463 }
464 
465 /*
466  * Initialize the nv_cmd_idx[] table.
467  */
468     void
469 init_normal_cmds()
470 {
471     int		i;
472 
473     /* Fill the index table with a one to one relation. */
474     for (i = 0; i < NV_CMDS_SIZE; ++i)
475 	nv_cmd_idx[i] = i;
476 
477     /* Sort the commands by the command character.  */
478     qsort((void *)&nv_cmd_idx, (size_t)NV_CMDS_SIZE, sizeof(short), nv_compare);
479 
480     /* Find the first entry that can't be indexed by the command character. */
481     for (i = 0; i < NV_CMDS_SIZE; ++i)
482 	if (i != nv_cmds[nv_cmd_idx[i]].cmd_char)
483 	    break;
484     nv_max_linear = i - 1;
485 }
486 
487 /*
488  * Search for a command in the commands table.
489  * Returns -1 for invalid command.
490  */
491     static int
492 find_command(cmdchar)
493     int		cmdchar;
494 {
495     int		i;
496     int		idx;
497     int		top, bot;
498     int		c;
499 
500 #ifdef FEAT_MBYTE
501     /* A multi-byte character is never a command. */
502     if (cmdchar >= 0x100)
503 	return -1;
504 #endif
505 
506     /* We use the absolute value of the character.  Special keys have a
507      * negative value, but are sorted on their absolute value. */
508     if (cmdchar < 0)
509 	cmdchar = -cmdchar;
510 
511     /* If the character is in the first part: The character is the index into
512      * nv_cmd_idx[]. */
513     if (cmdchar <= nv_max_linear)
514 	return nv_cmd_idx[cmdchar];
515 
516     /* Perform a binary search. */
517     bot = nv_max_linear + 1;
518     top = NV_CMDS_SIZE - 1;
519     idx = -1;
520     while (bot <= top)
521     {
522 	i = (top + bot) / 2;
523 	c = nv_cmds[nv_cmd_idx[i]].cmd_char;
524 	if (c < 0)
525 	    c = -c;
526 	if (cmdchar == c)
527 	{
528 	    idx = nv_cmd_idx[i];
529 	    break;
530 	}
531 	if (cmdchar > c)
532 	    bot = i + 1;
533 	else
534 	    top = i - 1;
535     }
536     return idx;
537 }
538 
539 /*
540  * Execute a command in Normal mode.
541  */
542 /*ARGSUSED*/
543     void
544 normal_cmd(oap, toplevel)
545     oparg_T	*oap;
546     int		toplevel;		/* TRUE when called from main() */
547 {
548     static long	opcount = 0;		/* ca.opcount saved here */
549     cmdarg_T	ca;			/* command arguments */
550     int		c;
551     int		ctrl_w = FALSE;		/* got CTRL-W command */
552     int		old_col = curwin->w_curswant;
553 #ifdef FEAT_CMDL_INFO
554     int		need_flushbuf;		/* need to call out_flush() */
555 #endif
556 #ifdef FEAT_VISUAL
557     pos_T	old_pos;		/* cursor position before command */
558     int		mapped_len;
559 #endif
560     static int	old_mapped_len = 0;
561     int		idx;
562 
563     vim_memset(&ca, 0, sizeof(ca));	/* also resets ca.retval */
564     ca.oap = oap;
565     ca.opcount = opcount;
566 
567 #ifdef FEAT_SNIFF
568     want_sniff_request = sniff_connected;
569 #endif
570 
571     /*
572      * If there is an operator pending, then the command we take this time
573      * will terminate it. Finish_op tells us to finish the operation before
574      * returning this time (unless the operation was cancelled).
575      */
576 #ifdef CURSOR_SHAPE
577     c = finish_op;
578 #endif
579     finish_op = (oap->op_type != OP_NOP);
580 #ifdef CURSOR_SHAPE
581     if (finish_op != c)
582     {
583 	ui_cursor_shape();		/* may show different cursor shape */
584 # ifdef FEAT_MOUSESHAPE
585 	update_mouseshape(-1);
586 # endif
587     }
588 #endif
589 
590     if (!finish_op && !oap->regname)
591 	ca.opcount = 0;
592 
593 #ifdef FEAT_VISUAL
594     mapped_len = typebuf_maplen();
595 #endif
596 
597     State = NORMAL_BUSY;
598 #ifdef USE_ON_FLY_SCROLL
599     dont_scroll = FALSE;	/* allow scrolling here */
600 #endif
601 
602     /*
603      * Get the command character from the user.
604      */
605     c = safe_vgetc();
606 
607 #ifdef FEAT_LANGMAP
608     LANGMAP_ADJUST(c, TRUE);
609 #endif
610 
611     /*
612      * If a mapping was started in Visual or Select mode, remember the length
613      * of the mapping.  This is used below to not return to Insert mode for as
614      * long as the mapping is being executed.
615      */
616     if (restart_edit == 0)
617 	old_mapped_len = 0;
618     else if (old_mapped_len
619 #ifdef FEAT_VISUAL
620 	    || (VIsual_active && mapped_len == 0 && typebuf_maplen() > 0)
621 #endif
622 	    )
623 	old_mapped_len = typebuf_maplen();
624 
625     if (c == NUL)
626 	c = K_ZERO;
627 
628 #ifdef FEAT_VISUAL
629     /*
630      * In Select mode, typed text replaces the selection.
631      */
632     if (VIsual_active
633 	    && VIsual_select
634 	    && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER))
635     {
636 # ifdef FEAT_MBYTE
637 	char_u	    buf[MB_MAXBYTES + 1];
638 
639 	buf[(*mb_char2bytes)(c, buf)] = NUL;
640 # else
641 	char_u	    buf[2];
642 
643 	buf[0] = c;
644 	buf[1] = NUL;
645 # endif
646 	/* Fake a "c"hange command.
647 	 * Insert the typed character in the typeahead buffer, so that it will
648 	 * be mapped in Insert mode.  Required for ":lmap" to work.  May cause
649 	 * mapping a character from ":vnoremap"... */
650 	(void)ins_typebuf(buf, REMAP_YES, 0, !KeyTyped, FALSE);
651 	c = 'c';
652     }
653 #endif
654 
655 #ifdef FEAT_CMDL_INFO
656     need_flushbuf = add_to_showcmd(c);
657 #endif
658 
659 getcount:
660 #ifdef FEAT_VISUAL
661     if (!(VIsual_active && VIsual_select))
662 #endif
663     {
664 	/*
665 	 * Handle a count before a command and compute ca.count0.
666 	 * Note that '0' is a command and not the start of a count, but it's
667 	 * part of a count after other digits.
668 	 */
669 	while (    (c >= '1' && c <= '9')
670 		|| (ca.count0 != 0 && (c == K_DEL || c == K_KDEL || c == '0')))
671 	{
672 	    if (c == K_DEL || c == K_KDEL)
673 	    {
674 		ca.count0 /= 10;
675 #ifdef FEAT_CMDL_INFO
676 		del_from_showcmd(4);	/* delete the digit and ~@% */
677 #endif
678 	    }
679 	    else
680 		ca.count0 = ca.count0 * 10 + (c - '0');
681 	    if (ca.count0 < 0)	    /* got too large! */
682 		ca.count0 = 999999999L;
683 	    if (ctrl_w)
684 	    {
685 		++no_mapping;
686 		++allow_keys;		/* no mapping for nchar, but keys */
687 	    }
688 	    ++no_zero_mapping;		/* don't map zero here */
689 	    c = safe_vgetc();
690 #ifdef FEAT_LANGMAP
691 	    LANGMAP_ADJUST(c, TRUE);
692 #endif
693 	    --no_zero_mapping;
694 	    if (ctrl_w)
695 	    {
696 		--no_mapping;
697 		--allow_keys;
698 	    }
699 #ifdef FEAT_CMDL_INFO
700 	    need_flushbuf |= add_to_showcmd(c);
701 #endif
702 	}
703 
704 	/*
705 	 * If we got CTRL-W there may be a/another count
706 	 */
707 	if (c == Ctrl_W && !ctrl_w && oap->op_type == OP_NOP)
708 	{
709 	    ctrl_w = TRUE;
710 	    ca.opcount = ca.count0;	/* remember first count */
711 	    ca.count0 = 0;
712 	    ++no_mapping;
713 	    ++allow_keys;		/* no mapping for nchar, but keys */
714 	    c = safe_vgetc();		/* get next character */
715 #ifdef FEAT_LANGMAP
716 	    LANGMAP_ADJUST(c, TRUE);
717 #endif
718 	    --no_mapping;
719 	    --allow_keys;
720 #ifdef FEAT_CMDL_INFO
721 	    need_flushbuf |= add_to_showcmd(c);
722 #endif
723 	    goto getcount;		/* jump back */
724 	}
725     }
726 
727     /*
728      * If we're in the middle of an operator (including after entering a yank
729      * buffer with '"') AND we had a count before the operator, then that
730      * count overrides the current value of ca.count0.
731      * What this means effectively, is that commands like "3dw" get turned
732      * into "d3w" which makes things fall into place pretty neatly.
733      * If you give a count before AND after the operator, they are multiplied.
734      */
735     if (ca.opcount != 0)
736     {
737 	if (ca.count0)
738 	    ca.count0 *= ca.opcount;
739 	else
740 	    ca.count0 = ca.opcount;
741     }
742 
743     /*
744      * Always remember the count.  It will be set to zero (on the next call,
745      * above) when there is no pending operator.
746      * When called from main(), save the count for use by the "count" built-in
747      * variable.
748      */
749     ca.opcount = ca.count0;
750     ca.count1 = (ca.count0 == 0 ? 1 : ca.count0);
751 
752 #ifdef FEAT_EVAL
753     /*
754      * Only set v:count when called from main() and not a stuffed command.
755      */
756     if (toplevel && stuff_empty())
757 	set_vcount(ca.count0, ca.count1);
758 #endif
759 
760     /*
761      * Find the command character in the table of commands.
762      * For CTRL-W we already got nchar when looking for a count.
763      */
764     if (ctrl_w)
765     {
766 	ca.nchar = c;
767 	ca.cmdchar = Ctrl_W;
768     }
769     else
770 	ca.cmdchar = c;
771     idx = find_command(ca.cmdchar);
772     if (idx < 0)
773     {
774 	/* Not a known command: beep. */
775 	clearopbeep(oap);
776 	goto normal_end;
777     }
778 #ifdef FEAT_CMDWIN
779     if (cmdwin_type != 0 && (nv_cmds[idx].cmd_flags & NV_NCW))
780     {
781 	/* This command is not allowed in the cmdline window: beep. */
782 	clearopbeep(oap);
783 	EMSG(_(e_cmdwin));
784 	goto normal_end;
785     }
786 #endif
787 
788 #ifdef FEAT_VISUAL
789     /*
790      * In Visual/Select mode, a few keys are handled in a special way.
791      */
792     if (VIsual_active)
793     {
794 	/* when 'keymodel' contains "stopsel" may stop Select/Visual mode */
795 	if (km_stopsel
796 		&& (nv_cmds[idx].cmd_flags & NV_STS)
797 		&& !(mod_mask & MOD_MASK_SHIFT))
798 	{
799 	    end_visual_mode();
800 	    redraw_curbuf_later(INVERTED);
801 	}
802 
803 	/* Keys that work different when 'keymodel' contains "startsel" */
804 	if (km_startsel)
805 	{
806 	    if (nv_cmds[idx].cmd_flags & NV_SS)
807 	    {
808 		unshift_special(&ca);
809 		idx = find_command(ca.cmdchar);
810 	    }
811 	    else if ((nv_cmds[idx].cmd_flags & NV_SSS)
812 					       && (mod_mask & MOD_MASK_SHIFT))
813 	    {
814 		mod_mask &= ~MOD_MASK_SHIFT;
815 	    }
816 	}
817     }
818 #endif
819 
820 #ifdef FEAT_RIGHTLEFT
821     if (curwin->w_p_rl && KeyTyped && !KeyStuffed
822 					  && (nv_cmds[idx].cmd_flags & NV_RL))
823     {
824 	/* Invert horizontal movements and operations.  Only when typed by the
825 	 * user directly, not when the result of a mapping or "x" translated
826 	 * to "dl". */
827 	switch (ca.cmdchar)
828 	{
829 	    case 'l':	    ca.cmdchar = 'h'; break;
830 	    case K_RIGHT:   ca.cmdchar = K_LEFT; break;
831 	    case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break;
832 	    case K_C_RIGHT: ca.cmdchar = K_C_LEFT; break;
833 	    case 'h':	    ca.cmdchar = 'l'; break;
834 	    case K_LEFT:    ca.cmdchar = K_RIGHT; break;
835 	    case K_S_LEFT:  ca.cmdchar = K_S_RIGHT; break;
836 	    case K_C_LEFT:  ca.cmdchar = K_C_RIGHT; break;
837 	    case '>':	    ca.cmdchar = '<'; break;
838 	    case '<':	    ca.cmdchar = '>'; break;
839 	}
840 	idx = find_command(ca.cmdchar);
841     }
842 #endif
843 
844     /*
845      * Get an additional character if we need one.
846      */
847     if ((nv_cmds[idx].cmd_flags & NV_NCH)
848 	    && (((nv_cmds[idx].cmd_flags & NV_NCH_NOP) == NV_NCH_NOP
849 		    && oap->op_type == OP_NOP)
850 		|| (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW
851 		|| (ca.cmdchar == 'q'
852 		    && oap->op_type == OP_NOP
853 		    && !Recording
854 		    && !Exec_reg)
855 		|| ((ca.cmdchar == 'a' || ca.cmdchar == 'i')
856 		    && (oap->op_type != OP_NOP
857 #ifdef FEAT_VISUAL
858 			|| VIsual_active
859 #endif
860 		       ))))
861     {
862 	int	*cp;
863 	int	repl = FALSE;	/* get character for replace mode */
864 	int	lit = FALSE;	/* get extra character literally */
865 	int	langmap_active = FALSE;    /* using :lmap mappings */
866 	int	lang;		/* getting a text character */
867 #ifdef USE_IM_CONTROL
868 	int	save_smd;	/* saved value of p_smd */
869 #endif
870 
871 	++no_mapping;
872 	++allow_keys;		/* no mapping for nchar, but allow key codes */
873 	if (ca.cmdchar == 'g')
874 	{
875 	    /*
876 	     * For 'g' get the next character now, so that we can check for
877 	     * "gr", "g'" and "g`".
878 	     */
879 	    ca.nchar = safe_vgetc();
880 #ifdef FEAT_LANGMAP
881 	    LANGMAP_ADJUST(ca.nchar, TRUE);
882 #endif
883 #ifdef FEAT_CMDL_INFO
884 	    need_flushbuf |= add_to_showcmd(ca.nchar);
885 #endif
886 	    if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`'
887 						      || ca.nchar == Ctrl_BSL)
888 	    {
889 		cp = &ca.extra_char;	/* need to get a third character */
890 		if (ca.nchar != 'r')
891 		    lit = TRUE;			/* get it literally */
892 		else
893 		    repl = TRUE;		/* get it in replace mode */
894 	    }
895 	    else
896 		cp = NULL;		/* no third character needed */
897 	}
898 	else
899 	{
900 	    if (ca.cmdchar == 'r')		/* get it in replace mode */
901 		repl = TRUE;
902 	    cp = &ca.nchar;
903 	}
904 	lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG));
905 
906 	/*
907 	 * Get a second or third character.
908 	 */
909 	if (cp != NULL)
910 	{
911 #ifdef CURSOR_SHAPE
912 	    if (repl)
913 	    {
914 		State = REPLACE;	/* pretend Replace mode */
915 		ui_cursor_shape();	/* show different cursor shape */
916 	    }
917 #endif
918 	    if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP)
919 	    {
920 		/* Allow mappings defined with ":lmap". */
921 		--no_mapping;
922 		--allow_keys;
923 		if (repl)
924 		    State = LREPLACE;
925 		else
926 		    State = LANGMAP;
927 		langmap_active = TRUE;
928 	    }
929 #ifdef USE_IM_CONTROL
930 	    save_smd = p_smd;
931 	    p_smd = FALSE;	/* Don't let the IM code show the mode here */
932 	    if (lang && curbuf->b_p_iminsert == B_IMODE_IM)
933 		im_set_active(TRUE);
934 #endif
935 
936 	    *cp = safe_vgetc();
937 
938 	    if (langmap_active)
939 	    {
940 		/* Undo the decrement done above */
941 		++no_mapping;
942 		++allow_keys;
943 		State = NORMAL_BUSY;
944 	    }
945 #ifdef USE_IM_CONTROL
946 	    if (lang)
947 	    {
948 		if (curbuf->b_p_iminsert != B_IMODE_LMAP)
949 		    im_save_status(&curbuf->b_p_iminsert);
950 		im_set_active(FALSE);
951 	    }
952 	    p_smd = save_smd;
953 #endif
954 #ifdef CURSOR_SHAPE
955 	    State = NORMAL_BUSY;
956 #endif
957 #ifdef FEAT_CMDL_INFO
958 	    need_flushbuf |= add_to_showcmd(*cp);
959 #endif
960 
961 	    if (!lit)
962 	    {
963 #ifdef FEAT_DIGRAPHS
964 		/* Typing CTRL-K gets a digraph. */
965 		if (*cp == Ctrl_K
966 			&& ((nv_cmds[idx].cmd_flags & NV_LANG)
967 			    || cp == &ca.extra_char)
968 			&& vim_strchr(p_cpo, CPO_DIGRAPH) == NULL)
969 		{
970 		    c = get_digraph(FALSE);
971 		    if (c > 0)
972 		    {
973 			*cp = c;
974 # ifdef FEAT_CMDL_INFO
975 			/* Guessing how to update showcmd here... */
976 			del_from_showcmd(3);
977 			need_flushbuf |= add_to_showcmd(*cp);
978 # endif
979 		    }
980 		}
981 #endif
982 
983 #ifdef FEAT_LANGMAP
984 		/* adjust chars > 127, except after "tTfFr" commands */
985 		LANGMAP_ADJUST(*cp, !lang);
986 #endif
987 #ifdef FEAT_RIGHTLEFT
988 		/* adjust Hebrew mapped char */
989 		if (p_hkmap && lang && KeyTyped)
990 		    *cp = hkmap(*cp);
991 # ifdef FEAT_FKMAP
992 		/* adjust Farsi mapped char */
993 		if (p_fkmap && lang && KeyTyped)
994 		    *cp = fkmap(*cp);
995 # endif
996 #endif
997 	    }
998 
999 	    /*
1000 	     * When the next character is CTRL-\ a following CTRL-N means the
1001 	     * command is aborted and we go to Normal mode.
1002 	     */
1003 	    if (cp == &ca.extra_char
1004 		    && ca.nchar == Ctrl_BSL
1005 		    && (ca.extra_char == Ctrl_N || ca.extra_char == Ctrl_G))
1006 	    {
1007 		ca.cmdchar = Ctrl_BSL;
1008 		ca.nchar = ca.extra_char;
1009 		idx = find_command(ca.cmdchar);
1010 	    }
1011 	    else if (*cp == Ctrl_BSL)
1012 	    {
1013 		long towait = (p_ttm >= 0 ? p_ttm : p_tm);
1014 
1015 		/* There is a busy wait here when typing "f<C-\>" and then
1016 		 * something different from CTRL-N.  Can't be avoided. */
1017 		while ((c = vpeekc()) <= 0 && towait > 0L)
1018 		{
1019 		    do_sleep(towait > 50L ? 50L : towait);
1020 		    towait -= 50L;
1021 		}
1022 		if (c > 0)
1023 		{
1024 		    c = safe_vgetc();
1025 		    if (c != Ctrl_N && c != Ctrl_G)
1026 			vungetc(c);
1027 		    else
1028 		    {
1029 			ca.cmdchar = Ctrl_BSL;
1030 			ca.nchar = c;
1031 			idx = find_command(ca.cmdchar);
1032 		    }
1033 		}
1034 	    }
1035 
1036 #ifdef FEAT_MBYTE
1037 	    /* When getting a text character and the next character is a
1038 	     * multi-byte character, it could be a composing character.
1039 	     * However, don't wait for it to arrive. */
1040 	    while (enc_utf8 && lang && (c = vpeekc()) > 0
1041 				 && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1))
1042 	    {
1043 		c = safe_vgetc();
1044 		if (!utf_iscomposing(c))
1045 		{
1046 		    vungetc(c);		/* it wasn't, put it back */
1047 		    break;
1048 		}
1049 		else if (ca.ncharC1 == 0)
1050 		    ca.ncharC1 = c;
1051 		else
1052 		    ca.ncharC2 = c;
1053 	    }
1054 #endif
1055 	}
1056 	--no_mapping;
1057 	--allow_keys;
1058     }
1059 
1060 #ifdef FEAT_CMDL_INFO
1061     /*
1062      * Flush the showcmd characters onto the screen so we can see them while
1063      * the command is being executed.  Only do this when the shown command was
1064      * actually displayed, otherwise this will slow down a lot when executing
1065      * mappings.
1066      */
1067     if (need_flushbuf)
1068 	out_flush();
1069 #endif
1070 
1071     State = NORMAL;
1072 
1073     if (ca.nchar == ESC)
1074     {
1075 	clearop(oap);
1076 	if (restart_edit == 0 && goto_im())
1077 	    restart_edit = 'a';
1078 	goto normal_end;
1079     }
1080 
1081     if (ca.cmdchar != K_IGNORE)
1082     {
1083 	msg_didout = FALSE;    /* don't scroll screen up for normal command */
1084 	msg_col = 0;
1085     }
1086 
1087 #ifdef FEAT_VISUAL
1088     old_pos = curwin->w_cursor;		/* remember where cursor was */
1089 
1090     /* When 'keymodel' contains "startsel" some keys start Select/Visual
1091      * mode. */
1092     if (!VIsual_active && km_startsel)
1093     {
1094 	if (nv_cmds[idx].cmd_flags & NV_SS)
1095 	{
1096 	    start_selection();
1097 	    unshift_special(&ca);
1098 	    idx = find_command(ca.cmdchar);
1099 	}
1100 	else if ((nv_cmds[idx].cmd_flags & NV_SSS)
1101 					   && (mod_mask & MOD_MASK_SHIFT))
1102 	{
1103 	    start_selection();
1104 	    mod_mask &= ~MOD_MASK_SHIFT;
1105 	}
1106     }
1107 #endif
1108 
1109     /*
1110      * Execute the command!
1111      * Call the command function found in the commands table.
1112      */
1113     ca.arg = nv_cmds[idx].cmd_arg;
1114     (nv_cmds[idx].cmd_func)(&ca);
1115 
1116     /*
1117      * If we didn't start or finish an operator, reset oap->regname, unless we
1118      * need it later.
1119      */
1120     if (!finish_op
1121 	    && !oap->op_type
1122 	    && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG)))
1123     {
1124 	clearop(oap);
1125 #ifdef FEAT_EVAL
1126 	set_reg_var('"');
1127 #endif
1128     }
1129 
1130     /*
1131      * If an operation is pending, handle it...
1132      */
1133     do_pending_operator(&ca, old_col, FALSE);
1134 
1135     /*
1136      * Wait for a moment when a message is displayed that will be overwritten
1137      * by the mode message.
1138      * In Visual mode and with "^O" in Insert mode, a short message will be
1139      * overwritten by the mode message.  Wait a bit, until a key is hit.
1140      * In Visual mode, it's more important to keep the Visual area updated
1141      * than keeping a message (e.g. from a /pat search).
1142      * Only do this if the command was typed, not from a mapping.
1143      * Don't wait when emsg_silent is non-zero.
1144      * Also wait a bit after an error message, e.g. for "^O:".
1145      * Don't redraw the screen, it would remove the message.
1146      */
1147     if (       ((p_smd
1148 		    && (restart_edit != 0
1149 #ifdef FEAT_VISUAL
1150 			|| (VIsual_active
1151 			    && old_pos.lnum == curwin->w_cursor.lnum
1152 			    && old_pos.col == curwin->w_cursor.col)
1153 #endif
1154 		       )
1155 		    && (clear_cmdline
1156 			|| redraw_cmdline)
1157 		    && (msg_didout || (msg_didany && msg_scroll))
1158 		    && !msg_nowait
1159 		    && KeyTyped)
1160 		|| (restart_edit != 0
1161 #ifdef FEAT_VISUAL
1162 		    && !VIsual_active
1163 #endif
1164 		    && (msg_scroll
1165 			|| emsg_on_display)))
1166 	    && oap->regname == 0
1167 	    && !(ca.retval & CA_COMMAND_BUSY)
1168 	    && stuff_empty()
1169 	    && typebuf_typed()
1170 	    && emsg_silent == 0
1171 	    && !did_wait_return
1172 	    && oap->op_type == OP_NOP)
1173     {
1174 	int	save_State = State;
1175 
1176 	/* Draw the cursor with the right shape here */
1177 	if (restart_edit != 0)
1178 	    State = INSERT;
1179 
1180 	/* If need to redraw, and there is a "keep_msg", redraw before the
1181 	 * delay */
1182 	if (must_redraw && keep_msg != NULL && !emsg_on_display)
1183 	{
1184 	    char_u	*kmsg;
1185 
1186 	    kmsg = keep_msg;
1187 	    keep_msg = NULL;
1188 	    /* showmode() will clear keep_msg, but we want to use it anyway */
1189 	    update_screen(0);
1190 	    /* now reset it, otherwise it's put in the history again */
1191 	    keep_msg = kmsg;
1192 	    msg_attr(kmsg, keep_msg_attr);
1193 	    vim_free(kmsg);
1194 	}
1195 	setcursor();
1196 	cursor_on();
1197 	out_flush();
1198 	if (msg_scroll || emsg_on_display)
1199 	    ui_delay(1000L, TRUE);	/* wait at least one second */
1200 	ui_delay(3000L, FALSE);		/* wait up to three seconds */
1201 	State = save_State;
1202 
1203 	msg_scroll = FALSE;
1204 	emsg_on_display = FALSE;
1205     }
1206 
1207     /*
1208      * Finish up after executing a Normal mode command.
1209      */
1210 normal_end:
1211 
1212     msg_nowait = FALSE;
1213 
1214     /* Reset finish_op, in case it was set */
1215 #ifdef CURSOR_SHAPE
1216     c = finish_op;
1217 #endif
1218     finish_op = FALSE;
1219 #ifdef CURSOR_SHAPE
1220     /* Redraw the cursor with another shape, if we were in Operator-pending
1221      * mode or did a replace command. */
1222     if (c || ca.cmdchar == 'r')
1223     {
1224 	ui_cursor_shape();		/* may show different cursor shape */
1225 # ifdef FEAT_MOUSESHAPE
1226 	update_mouseshape(-1);
1227 # endif
1228     }
1229 #endif
1230 
1231 #ifdef FEAT_CMDL_INFO
1232     if (oap->op_type == OP_NOP && oap->regname == 0)
1233 	clear_showcmd();
1234 #endif
1235 
1236     checkpcmark();		/* check if we moved since setting pcmark */
1237     vim_free(ca.searchbuf);
1238 
1239 #ifdef FEAT_MBYTE
1240     if (has_mbyte)
1241 	mb_adjust_cursor();
1242 #endif
1243 
1244 #ifdef FEAT_SCROLLBIND
1245     if (curwin->w_p_scb && toplevel)
1246     {
1247 	validate_cursor();	/* may need to update w_leftcol */
1248 	do_check_scrollbind(TRUE);
1249     }
1250 #endif
1251 
1252     /*
1253      * May restart edit(), if we got here with CTRL-O in Insert mode (but not
1254      * if still inside a mapping that started in Visual mode).
1255      * May switch from Visual to Select mode after CTRL-O command.
1256      */
1257     if (       oap->op_type == OP_NOP
1258 #ifdef FEAT_VISUAL
1259 	    && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
1260 		|| restart_VIsual_select == 1)
1261 #endif
1262 	    && !(ca.retval & CA_COMMAND_BUSY)
1263 	    && stuff_empty()
1264 	    && oap->regname == 0)
1265     {
1266 #ifdef FEAT_VISUAL
1267 	if (restart_VIsual_select == 1)
1268 	{
1269 	    VIsual_select = TRUE;
1270 	    showmode();
1271 	    restart_VIsual_select = 0;
1272 	}
1273 #endif
1274 	if (restart_edit != 0
1275 #ifdef FEAT_VISUAL
1276 		&& !VIsual_active
1277 #endif
1278 		&& old_mapped_len == 0)
1279 	    (void)edit(restart_edit, FALSE, 1L);
1280     }
1281 
1282 #ifdef FEAT_VISUAL
1283     if (restart_VIsual_select == 2)
1284 	restart_VIsual_select = 1;
1285 #endif
1286 
1287     /* Save count before an operator for next time. */
1288     opcount = ca.opcount;
1289 }
1290 
1291 /*
1292  * Handle an operator after visual mode or when the movement is finished
1293  */
1294     void
1295 do_pending_operator(cap, old_col, gui_yank)
1296     cmdarg_T	*cap;
1297     int		old_col;
1298     int		gui_yank;
1299 {
1300     oparg_T	*oap = cap->oap;
1301     pos_T	old_cursor;
1302     int		empty_region_error;
1303     int		restart_edit_save;
1304 
1305 #ifdef FEAT_VISUAL
1306     /* The visual area is remembered for redo */
1307     static int	    redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
1308     static linenr_T redo_VIsual_line_count; /* number of lines */
1309     static colnr_T  redo_VIsual_col;	    /* number of cols or end column */
1310     static long	    redo_VIsual_count;	    /* count for Visual operator */
1311 # ifdef FEAT_VIRTUALEDIT
1312     int		    include_line_break = FALSE;
1313 # endif
1314 #endif
1315 
1316 #if defined(FEAT_CLIPBOARD)
1317     /*
1318      * Yank the visual area into the GUI selection register before we operate
1319      * on it and lose it forever.
1320      * Don't do it if a specific register was specified, so that ""x"*P works.
1321      * This could call do_pending_operator() recursively, but that's OK
1322      * because gui_yank will be TRUE for the nested call.
1323      */
1324     if (clip_star.available
1325 	    && oap->op_type != OP_NOP
1326 	    && !gui_yank
1327 # ifdef FEAT_VISUAL
1328 	    && VIsual_active
1329 	    && !redo_VIsual_busy
1330 # endif
1331 	    && oap->regname == 0)
1332 	clip_auto_select();
1333 #endif
1334     old_cursor = curwin->w_cursor;
1335 
1336     /*
1337      * If an operation is pending, handle it...
1338      */
1339     if ((finish_op
1340 #ifdef FEAT_VISUAL
1341 		|| VIsual_active
1342 #endif
1343 		) && oap->op_type != OP_NOP)
1344     {
1345 #ifdef FEAT_VISUAL
1346 	oap->is_VIsual = VIsual_active;
1347 	if (oap->motion_force == 'V')
1348 	    oap->motion_type = MLINE;
1349 	else if (oap->motion_force == 'v')
1350 	{
1351 	    /* If the motion was linewise, "inclusive" will not have been set.
1352 	     * Use "exclusive" to be consistent.  Makes "dvj" work nice. */
1353 	    if (oap->motion_type == MLINE)
1354 		oap->inclusive = FALSE;
1355 	    /* If the motion already was characterwise, toggle "inclusive" */
1356 	    else if (oap->motion_type == MCHAR)
1357 		oap->inclusive = !oap->inclusive;
1358 	    oap->motion_type = MCHAR;
1359 	}
1360 	else if (oap->motion_force == Ctrl_V)
1361 	{
1362 	    /* Change line- or characterwise motion into Visual block mode. */
1363 	    VIsual_active = TRUE;
1364 	    VIsual = oap->start;
1365 	    VIsual_mode = Ctrl_V;
1366 	    VIsual_select = FALSE;
1367 	    VIsual_reselect = FALSE;
1368 	}
1369 #endif
1370 
1371 	/* only redo yank when 'y' flag is in 'cpoptions' */
1372 	/* never redo "zf" (define fold) */
1373 	if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
1374 #ifdef FEAT_VISUAL
1375 		&& (!VIsual_active || oap->motion_force)
1376 #endif
1377 #ifdef FEAT_FOLDING
1378 		&& oap->op_type != OP_FOLD
1379 		&& oap->op_type != OP_FOLDOPEN
1380 		&& oap->op_type != OP_FOLDOPENREC
1381 		&& oap->op_type != OP_FOLDCLOSE
1382 		&& oap->op_type != OP_FOLDCLOSEREC
1383 		&& oap->op_type != OP_FOLDDEL
1384 		&& oap->op_type != OP_FOLDDELREC
1385 #endif
1386 		)
1387 	{
1388 	    prep_redo(oap->regname, cap->count0,
1389 		    get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
1390 		    oap->motion_force, cap->cmdchar, cap->nchar);
1391 	    if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */
1392 	    {
1393 		/*
1394 		 * If 'cpoptions' does not contain 'r', insert the search
1395 		 * pattern to really repeat the same command.
1396 		 */
1397 		if (vim_strchr(p_cpo, CPO_REDO) == NULL)
1398 		    AppendToRedobuffLit(cap->searchbuf);
1399 		AppendToRedobuff(NL_STR);
1400 	    }
1401 	    else if (cap->cmdchar == ':')
1402 	    {
1403 		/* do_cmdline() has stored the first typed line in
1404 		 * "repeat_cmdline".  When several lines are typed repeating
1405 		 * won't be possible. */
1406 		if (repeat_cmdline == NULL)
1407 		    ResetRedobuff();
1408 		else
1409 		{
1410 		    AppendToRedobuffLit(repeat_cmdline);
1411 		    AppendToRedobuff(NL_STR);
1412 		    vim_free(repeat_cmdline);
1413 		    repeat_cmdline = NULL;
1414 		}
1415 	    }
1416 	}
1417 
1418 #ifdef FEAT_VISUAL
1419 	if (redo_VIsual_busy)
1420 	{
1421 	    oap->start = curwin->w_cursor;
1422 	    curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
1423 	    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1424 		curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1425 	    VIsual_mode = redo_VIsual_mode;
1426 	    if (VIsual_mode == 'v')
1427 	    {
1428 		if (redo_VIsual_line_count <= 1)
1429 		    curwin->w_cursor.col += redo_VIsual_col - 1;
1430 		else
1431 		    curwin->w_cursor.col = redo_VIsual_col;
1432 	    }
1433 	    if (redo_VIsual_col == MAXCOL)
1434 	    {
1435 		curwin->w_curswant = MAXCOL;
1436 		coladvance((colnr_T)MAXCOL);
1437 	    }
1438 	    cap->count0 = redo_VIsual_count;
1439 	    if (redo_VIsual_count != 0)
1440 		cap->count1 = redo_VIsual_count;
1441 	    else
1442 		cap->count1 = 1;
1443 	}
1444 	else if (VIsual_active)
1445 	{
1446 	    /* Save the current VIsual area for '< and '> marks, and "gv" */
1447 	    curbuf->b_visual_start = VIsual;
1448 	    curbuf->b_visual_end = curwin->w_cursor;
1449 	    curbuf->b_visual_mode = VIsual_mode;
1450 # ifdef FEAT_EVAL
1451 	    curbuf->b_visual_mode_eval = VIsual_mode;
1452 # endif
1453 	    curbuf->b_visual_curswant = curwin->w_curswant;
1454 
1455 	    /* In Select mode, a linewise selection is operated upon like a
1456 	     * characterwise selection. */
1457 	    if (VIsual_select && VIsual_mode == 'V')
1458 	    {
1459 		if (lt(VIsual, curwin->w_cursor))
1460 		{
1461 		    VIsual.col = 0;
1462 		    curwin->w_cursor.col =
1463 			       (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum));
1464 		}
1465 		else
1466 		{
1467 		    curwin->w_cursor.col = 0;
1468 		    VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum));
1469 		}
1470 		VIsual_mode = 'v';
1471 	    }
1472 	    /* If 'selection' is "exclusive", backup one character for
1473 	     * charwise selections. */
1474 	    else if (VIsual_mode == 'v')
1475 	    {
1476 # ifdef FEAT_VIRTUALEDIT
1477 		include_line_break =
1478 # endif
1479 		    unadjust_for_sel();
1480 	    }
1481 
1482 	    oap->start = VIsual;
1483 	    if (VIsual_mode == 'V')
1484 		oap->start.col = 0;
1485 	}
1486 #endif /* FEAT_VISUAL */
1487 
1488 	/*
1489 	 * Set oap->start to the first position of the operated text, oap->end
1490 	 * to the end of the operated text.  w_cursor is equal to oap->start.
1491 	 */
1492 	if (lt(oap->start, curwin->w_cursor))
1493 	{
1494 #ifdef FEAT_FOLDING
1495 	    /* Include folded lines completely. */
1496 	    if (!VIsual_active)
1497 	    {
1498 		if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL))
1499 		    oap->start.col = 0;
1500 		if (hasFolding(curwin->w_cursor.lnum, NULL,
1501 						      &curwin->w_cursor.lnum))
1502 		    curwin->w_cursor.col = (colnr_T)STRLEN(ml_get_curline());
1503 	    }
1504 #endif
1505 	    oap->end = curwin->w_cursor;
1506 	    curwin->w_cursor = oap->start;
1507 
1508 	    /* w_virtcol may have been updated; if the cursor goes back to its
1509 	     * previous position w_virtcol becomes invalid and isn't updated
1510 	     * automatically. */
1511 	    curwin->w_valid &= ~VALID_VIRTCOL;
1512 	}
1513 	else
1514 	{
1515 #ifdef FEAT_FOLDING
1516 	    /* Include folded lines completely. */
1517 	    if (!VIsual_active && oap->motion_type == MLINE)
1518 	    {
1519 		if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum,
1520 									NULL))
1521 		    curwin->w_cursor.col = 0;
1522 		if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum))
1523 		    oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum));
1524 	    }
1525 #endif
1526 	    oap->end = oap->start;
1527 	    oap->start = curwin->w_cursor;
1528 	}
1529 
1530 	oap->line_count = oap->end.lnum - oap->start.lnum + 1;
1531 
1532 #ifdef FEAT_VIRTUALEDIT
1533 	/* Set "virtual_op" before resetting VIsual_active. */
1534 	virtual_op = virtual_active();
1535 #endif
1536 
1537 #ifdef FEAT_VISUAL
1538 	if (VIsual_active || redo_VIsual_busy)
1539 	{
1540 	    if (VIsual_mode == Ctrl_V)	/* block mode */
1541 	    {
1542 		colnr_T	    start, end;
1543 
1544 		oap->block_mode = TRUE;
1545 
1546 		getvvcol(curwin, &(oap->start),
1547 				      &oap->start_vcol, NULL, &oap->end_vcol);
1548 		if (!redo_VIsual_busy)
1549 		{
1550 		    getvvcol(curwin, &(oap->end), &start, NULL, &end);
1551 
1552 		    if (start < oap->start_vcol)
1553 			oap->start_vcol = start;
1554 		    if (end > oap->end_vcol)
1555 		    {
1556 			if (*p_sel == 'e' && start >= 1
1557 						&& start - 1 >= oap->end_vcol)
1558 			    oap->end_vcol = start - 1;
1559 			else
1560 			    oap->end_vcol = end;
1561 		    }
1562 		}
1563 
1564 		/* if '$' was used, get oap->end_vcol from longest line */
1565 		if (curwin->w_curswant == MAXCOL)
1566 		{
1567 		    curwin->w_cursor.col = MAXCOL;
1568 		    oap->end_vcol = 0;
1569 		    for (curwin->w_cursor.lnum = oap->start.lnum;
1570 			    curwin->w_cursor.lnum <= oap->end.lnum;
1571 						      ++curwin->w_cursor.lnum)
1572 		    {
1573 			getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
1574 			if (end > oap->end_vcol)
1575 			    oap->end_vcol = end;
1576 		    }
1577 		}
1578 		else if (redo_VIsual_busy)
1579 		    oap->end_vcol = oap->start_vcol + redo_VIsual_col - 1;
1580 		/*
1581 		 * Correct oap->end.col and oap->start.col to be the
1582 		 * upper-left and lower-right corner of the block area.
1583 		 *
1584 		 * (Actually, this does convert column positions into character
1585 		 * positions)
1586 		 */
1587 		curwin->w_cursor.lnum = oap->end.lnum;
1588 		coladvance(oap->end_vcol);
1589 		oap->end = curwin->w_cursor;
1590 
1591 		curwin->w_cursor = oap->start;
1592 		coladvance(oap->start_vcol);
1593 		oap->start = curwin->w_cursor;
1594 	    }
1595 
1596 	    if (!redo_VIsual_busy && !gui_yank)
1597 	    {
1598 		/*
1599 		 * Prepare to reselect and redo Visual: this is based on the
1600 		 * size of the Visual text
1601 		 */
1602 		resel_VIsual_mode = VIsual_mode;
1603 		if (curwin->w_curswant == MAXCOL)
1604 		    resel_VIsual_col = MAXCOL;
1605 		else if (VIsual_mode == Ctrl_V)
1606 		    resel_VIsual_col = oap->end_vcol - oap->start_vcol + 1;
1607 		else if (oap->line_count > 1)
1608 		    resel_VIsual_col = oap->end.col;
1609 		else
1610 		    resel_VIsual_col = oap->end.col - oap->start.col + 1;
1611 		resel_VIsual_line_count = oap->line_count;
1612 	    }
1613 
1614 	    /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
1615 	    if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
1616 		    && oap->op_type != OP_COLON
1617 #ifdef FEAT_FOLDING
1618 		    && oap->op_type != OP_FOLD
1619 		    && oap->op_type != OP_FOLDOPEN
1620 		    && oap->op_type != OP_FOLDOPENREC
1621 		    && oap->op_type != OP_FOLDCLOSE
1622 		    && oap->op_type != OP_FOLDCLOSEREC
1623 		    && oap->op_type != OP_FOLDDEL
1624 		    && oap->op_type != OP_FOLDDELREC
1625 #endif
1626 		    && oap->motion_force == NUL
1627 		    )
1628 	    {
1629 		/* Prepare for redoing.  Only use the nchar field for "r",
1630 		 * otherwise it might be the second char of the operator. */
1631 		prep_redo(oap->regname, 0L, NUL, 'v',
1632 				get_op_char(oap->op_type),
1633 				get_extra_op_char(oap->op_type),
1634 				oap->op_type == OP_REPLACE ? cap->nchar : NUL);
1635 		if (!redo_VIsual_busy)
1636 		{
1637 		    redo_VIsual_mode = resel_VIsual_mode;
1638 		    redo_VIsual_col = resel_VIsual_col;
1639 		    redo_VIsual_line_count = resel_VIsual_line_count;
1640 		    redo_VIsual_count = cap->count0;
1641 		}
1642 	    }
1643 
1644 	    /*
1645 	     * oap->inclusive defaults to TRUE.
1646 	     * If oap->end is on a NUL (empty line) oap->inclusive becomes
1647 	     * FALSE.  This makes "d}P" and "v}dP" work the same.
1648 	     */
1649 	    if (oap->motion_force == NUL || oap->motion_type == MLINE)
1650 		oap->inclusive = TRUE;
1651 	    if (VIsual_mode == 'V')
1652 		oap->motion_type = MLINE;
1653 	    else
1654 	    {
1655 		oap->motion_type = MCHAR;
1656 		if (VIsual_mode != Ctrl_V && *ml_get_pos(&(oap->end)) == NUL
1657 # ifdef FEAT_VIRTUALEDIT
1658 			&& (include_line_break || !virtual_op)
1659 # endif
1660 			)
1661 		{
1662 		    oap->inclusive = FALSE;
1663 		    /* Try to include the newline, unless it's an operator
1664 		     * that works on lines only */
1665 		    if (*p_sel != 'o'
1666 			    && !op_on_lines(oap->op_type)
1667 			    && oap->end.lnum < curbuf->b_ml.ml_line_count)
1668 		    {
1669 			++oap->end.lnum;
1670 			oap->end.col = 0;
1671 # ifdef FEAT_VIRTUALEDIT
1672 			oap->end.coladd = 0;
1673 # endif
1674 			++oap->line_count;
1675 		    }
1676 		}
1677 	    }
1678 
1679 	    redo_VIsual_busy = FALSE;
1680 	    /*
1681 	     * Switch Visual off now, so screen updating does
1682 	     * not show inverted text when the screen is redrawn.
1683 	     * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
1684 	     * no screen redraw, so it is done here to remove the inverted
1685 	     * part.
1686 	     */
1687 	    if (!gui_yank)
1688 	    {
1689 		VIsual_active = FALSE;
1690 # ifdef FEAT_MOUSE
1691 		setmouse();
1692 		mouse_dragging = 0;
1693 # endif
1694 		if (p_smd)
1695 		    clear_cmdline = TRUE;   /* unshow visual mode later */
1696 #ifdef FEAT_CMDL_INFO
1697 		else
1698 		    clear_showcmd();
1699 #endif
1700 		if ((oap->op_type == OP_YANK
1701 			    || oap->op_type == OP_COLON
1702 			    || oap->op_type == OP_FILTER)
1703 			&& oap->motion_force == NUL)
1704 		    redraw_curbuf_later(INVERTED);
1705 	    }
1706 	}
1707 #endif
1708 
1709 #ifdef FEAT_MBYTE
1710 	/* Include the trailing byte of a multi-byte char. */
1711 	if (has_mbyte && oap->inclusive)
1712 	{
1713 	    int		l;
1714 
1715 	    l = (*mb_ptr2len_check)(ml_get_pos(&oap->end));
1716 	    if (l > 1)
1717 		oap->end.col += l - 1;
1718 	}
1719 #endif
1720 	curwin->w_set_curswant = TRUE;
1721 
1722 	/*
1723 	 * oap->empty is set when start and end are the same.  The inclusive
1724 	 * flag affects this too, unless yanking and the end is on a NUL.
1725 	 */
1726 	oap->empty = (oap->motion_type == MCHAR
1727 		    && (!oap->inclusive
1728 			|| (oap->op_type == OP_YANK
1729 			    && gchar_pos(&oap->end) == NUL))
1730 		    && equalpos(oap->start, oap->end)
1731 #ifdef FEAT_VIRTUALEDIT
1732 		    && !(virtual_op && oap->start.coladd != oap->end.coladd)
1733 #endif
1734 		    );
1735 	/*
1736 	 * For delete, change and yank, it's an error to operate on an
1737 	 * empty region, when 'E' included in 'cpoptions' (Vi compatible).
1738 	 */
1739 	empty_region_error = (oap->empty
1740 				&& vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
1741 
1742 #ifdef FEAT_VISUAL
1743 	/* Force a redraw when operating on an empty Visual region, when
1744 	 * 'modifiable is off or creating a fold. */
1745 	if (oap->is_VIsual && (oap->empty || !curbuf->b_p_ma
1746 # ifdef FEAT_FOLDING
1747 		    || oap->op_type == OP_FOLD
1748 # endif
1749 		    ))
1750 	    redraw_curbuf_later(INVERTED);
1751 #endif
1752 
1753 	/*
1754 	 * If the end of an operator is in column one while oap->motion_type
1755 	 * is MCHAR and oap->inclusive is FALSE, we put op_end after the last
1756 	 * character in the previous line. If op_start is on or before the
1757 	 * first non-blank in the line, the operator becomes linewise
1758 	 * (strange, but that's the way vi does it).
1759 	 */
1760 	if (	   oap->motion_type == MCHAR
1761 		&& oap->inclusive == FALSE
1762 		&& !(cap->retval & CA_NO_ADJ_OP_END)
1763 		&& oap->end.col == 0
1764 #ifdef FEAT_VISUAL
1765 		&& (!oap->is_VIsual || *p_sel == 'o')
1766 #endif
1767 		&& oap->line_count > 1)
1768 	{
1769 	    oap->end_adjusted = TRUE;	    /* remember that we did this */
1770 	    --oap->line_count;
1771 	    --oap->end.lnum;
1772 	    if (inindent(0))
1773 		oap->motion_type = MLINE;
1774 	    else
1775 	    {
1776 		oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
1777 		if (oap->end.col)
1778 		{
1779 		    --oap->end.col;
1780 		    oap->inclusive = TRUE;
1781 		}
1782 	    }
1783 	}
1784 	else
1785 	    oap->end_adjusted = FALSE;
1786 
1787 	switch (oap->op_type)
1788 	{
1789 	case OP_LSHIFT:
1790 	case OP_RSHIFT:
1791 	    op_shift(oap, TRUE,
1792 #ifdef FEAT_VISUAL
1793 		    oap->is_VIsual ? (int)cap->count1 :
1794 #endif
1795 		    1);
1796 	    auto_format(FALSE, TRUE);
1797 	    break;
1798 
1799 	case OP_JOIN_NS:
1800 	case OP_JOIN:
1801 	    if (oap->line_count < 2)
1802 		oap->line_count = 2;
1803 	    if (curwin->w_cursor.lnum + oap->line_count - 1 >
1804 						   curbuf->b_ml.ml_line_count)
1805 		beep_flush();
1806 	    else
1807 	    {
1808 		do_do_join(oap->line_count, oap->op_type == OP_JOIN);
1809 		auto_format(FALSE, TRUE);
1810 	    }
1811 	    break;
1812 
1813 	case OP_DELETE:
1814 #ifdef FEAT_VISUAL
1815 	    VIsual_reselect = FALSE;	    /* don't reselect now */
1816 #endif
1817 	    if (empty_region_error)
1818 		vim_beep();
1819 	    else
1820 	    {
1821 		(void)op_delete(oap);
1822 		if (oap->motion_type == MLINE && has_format_option(FO_AUTO))
1823 		    u_save_cursor();	    /* cursor line wasn't saved yet */
1824 		auto_format(FALSE, TRUE);
1825 	    }
1826 	    break;
1827 
1828 	case OP_YANK:
1829 	    if (empty_region_error)
1830 	    {
1831 		if (!gui_yank)
1832 		    vim_beep();
1833 	    }
1834 	    else
1835 		(void)op_yank(oap, FALSE, !gui_yank);
1836 	    check_cursor_col();
1837 	    break;
1838 
1839 	case OP_CHANGE:
1840 #ifdef FEAT_VISUAL
1841 	    VIsual_reselect = FALSE;	    /* don't reselect now */
1842 #endif
1843 	    if (empty_region_error)
1844 		vim_beep();
1845 	    else
1846 	    {
1847 		/* This is a new edit command, not a restart.  Need to
1848 		 * remember it to make 'insertmode' work with mappings for
1849 		 * Visual mode.  But do this only once and not when typed and
1850 		 * 'insertmode' isn't set. */
1851 		if (p_im || !KeyTyped)
1852 		    restart_edit_save = restart_edit;
1853 		else
1854 		    restart_edit_save = 0;
1855 		restart_edit = 0;
1856 		/* Reset finish_op now, don't want it set inside edit(). */
1857 		finish_op = FALSE;
1858 		if (op_change(oap))	/* will call edit() */
1859 		    cap->retval |= CA_COMMAND_BUSY;
1860 		if (restart_edit == 0)
1861 		    restart_edit = restart_edit_save;
1862 	    }
1863 	    break;
1864 
1865 	case OP_FILTER:
1866 	    if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
1867 		AppendToRedobuff((char_u *)"!\r");  /* use any last used !cmd */
1868 	    else
1869 		bangredo = TRUE;    /* do_bang() will put cmd in redo buffer */
1870 
1871 	case OP_INDENT:
1872 	case OP_COLON:
1873 
1874 #if defined(FEAT_LISP) || defined(FEAT_CINDENT)
1875 	    /*
1876 	     * If 'equalprg' is empty, do the indenting internally.
1877 	     */
1878 	    if (oap->op_type == OP_INDENT && *get_equalprg() == NUL)
1879 	    {
1880 # ifdef FEAT_LISP
1881 		if (curbuf->b_p_lisp)
1882 		{
1883 		    op_reindent(oap, get_lisp_indent);
1884 		    break;
1885 		}
1886 # endif
1887 # ifdef FEAT_CINDENT
1888 		op_reindent(oap,
1889 #  ifdef FEAT_EVAL
1890 			*curbuf->b_p_inde != NUL ? get_expr_indent :
1891 #  endif
1892 			    get_c_indent);
1893 		break;
1894 # endif
1895 	    }
1896 #endif
1897 
1898 	    op_colon(oap);
1899 	    break;
1900 
1901 	case OP_TILDE:
1902 	case OP_UPPER:
1903 	case OP_LOWER:
1904 	case OP_ROT13:
1905 	    if (empty_region_error)
1906 		vim_beep();
1907 	    else
1908 		op_tilde(oap);
1909 	    check_cursor_col();
1910 	    break;
1911 
1912 	case OP_FORMAT:
1913 	    if (*p_fp != NUL)
1914 		op_colon(oap);		/* use external command */
1915 	    else
1916 		op_format(oap, FALSE);	/* use internal function */
1917 	    break;
1918 
1919 	case OP_FORMAT2:
1920 	    op_format(oap, TRUE);	/* use internal function */
1921 	    break;
1922 
1923 	case OP_INSERT:
1924 	case OP_APPEND:
1925 #ifdef FEAT_VISUAL
1926 	    VIsual_reselect = FALSE;	/* don't reselect now */
1927 #endif
1928 #ifdef FEAT_VISUALEXTRA
1929 	    if (empty_region_error)
1930 		vim_beep();
1931 	    else
1932 	    {
1933 		/* This is a new edit command, not a restart.  Need to
1934 		 * remember it to make 'insertmode' work with mappings for
1935 		 * Visual mode.  But do this only once. */
1936 		restart_edit_save = restart_edit;
1937 		restart_edit = 0;
1938 
1939 		op_insert(oap, cap->count1);
1940 
1941 		/* TODO: when inserting in several lines, should format all
1942 		 * the lines. */
1943 		auto_format(FALSE, TRUE);
1944 
1945 		if (restart_edit == 0)
1946 		    restart_edit = restart_edit_save;
1947 	    }
1948 #else
1949 	    vim_beep();
1950 #endif
1951 	    break;
1952 
1953 	case OP_REPLACE:
1954 #ifdef FEAT_VISUAL
1955 	    VIsual_reselect = FALSE;	/* don't reselect now */
1956 #endif
1957 #ifdef FEAT_VISUALEXTRA
1958 	    if (empty_region_error)
1959 #endif
1960 		vim_beep();
1961 #ifdef FEAT_VISUALEXTRA
1962 	    else
1963 		op_replace(oap, cap->nchar);
1964 #endif
1965 	    break;
1966 
1967 #ifdef FEAT_FOLDING
1968 	case OP_FOLD:
1969 	    VIsual_reselect = FALSE;	/* don't reselect now */
1970 	    foldCreate(oap->start.lnum, oap->end.lnum);
1971 	    break;
1972 
1973 	case OP_FOLDOPEN:
1974 	case OP_FOLDOPENREC:
1975 	case OP_FOLDCLOSE:
1976 	case OP_FOLDCLOSEREC:
1977 	    VIsual_reselect = FALSE;	/* don't reselect now */
1978 	    opFoldRange(oap->start.lnum, oap->end.lnum,
1979 		    oap->op_type == OP_FOLDOPEN
1980 					    || oap->op_type == OP_FOLDOPENREC,
1981 		    oap->op_type == OP_FOLDOPENREC
1982 					  || oap->op_type == OP_FOLDCLOSEREC,
1983 					  oap->is_VIsual);
1984 	    break;
1985 
1986 	case OP_FOLDDEL:
1987 	case OP_FOLDDELREC:
1988 	    VIsual_reselect = FALSE;	/* don't reselect now */
1989 	    deleteFold(oap->start.lnum, oap->end.lnum,
1990 			       oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
1991 	    break;
1992 #endif
1993 	default:
1994 	    clearopbeep(oap);
1995 	}
1996 #ifdef FEAT_VIRTUALEDIT
1997 	virtual_op = MAYBE;
1998 #endif
1999 	if (!gui_yank)
2000 	{
2001 	    /*
2002 	     * if 'sol' not set, go back to old column for some commands
2003 	     */
2004 	    if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
2005 		    && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
2006 						|| oap->op_type == OP_DELETE))
2007 		coladvance(curwin->w_curswant = old_col);
2008 	}
2009 	else
2010 	{
2011 	    curwin->w_cursor = old_cursor;
2012 	}
2013 #ifdef FEAT_VISUAL
2014 	oap->block_mode = FALSE;
2015 #endif
2016 	clearop(oap);
2017     }
2018 }
2019 
2020 /*
2021  * Handle indent and format operators and visual mode ":".
2022  */
2023     static void
2024 op_colon(oap)
2025     oparg_T	*oap;
2026 {
2027     stuffcharReadbuff(':');
2028 #ifdef FEAT_VISUAL
2029     if (oap->is_VIsual)
2030 	stuffReadbuff((char_u *)"'<,'>");
2031     else
2032 #endif
2033     {
2034 	/*
2035 	 * Make the range look nice, so it can be repeated.
2036 	 */
2037 	if (oap->start.lnum == curwin->w_cursor.lnum)
2038 	    stuffcharReadbuff('.');
2039 	else
2040 	    stuffnumReadbuff((long)oap->start.lnum);
2041 	if (oap->end.lnum != oap->start.lnum)
2042 	{
2043 	    stuffcharReadbuff(',');
2044 	    if (oap->end.lnum == curwin->w_cursor.lnum)
2045 		stuffcharReadbuff('.');
2046 	    else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
2047 		stuffcharReadbuff('$');
2048 	    else if (oap->start.lnum == curwin->w_cursor.lnum)
2049 	    {
2050 		stuffReadbuff((char_u *)".+");
2051 		stuffnumReadbuff((long)oap->line_count - 1);
2052 	    }
2053 	    else
2054 		stuffnumReadbuff((long)oap->end.lnum);
2055 	}
2056     }
2057     if (oap->op_type != OP_COLON)
2058 	stuffReadbuff((char_u *)"!");
2059     if (oap->op_type == OP_INDENT)
2060     {
2061 #ifndef FEAT_CINDENT
2062 	if (*get_equalprg() == NUL)
2063 	    stuffReadbuff((char_u *)"indent");
2064 	else
2065 #endif
2066 	    stuffReadbuff(get_equalprg());
2067 	stuffReadbuff((char_u *)"\n");
2068     }
2069     else if (oap->op_type == OP_FORMAT)
2070     {
2071 	if (*p_fp == NUL)
2072 	    stuffReadbuff((char_u *)"fmt");
2073 	else
2074 	    stuffReadbuff(p_fp);
2075 	stuffReadbuff((char_u *)"\n");
2076     }
2077 
2078     /*
2079      * do_cmdline() does the rest
2080      */
2081 }
2082 
2083 #if defined(FEAT_MOUSE) || defined(PROTO)
2084 /*
2085  * Do the appropriate action for the current mouse click in the current mode.
2086  * Not used for Command-line mode.
2087  *
2088  * Normal Mode:
2089  * event	 modi-	position      visual	   change   action
2090  *		 fier	cursor			   window
2091  * left press	  -	yes	    end		    yes
2092  * left press	  C	yes	    end		    yes	    "^]" (2)
2093  * left press	  S	yes	    end		    yes	    "*" (2)
2094  * left drag	  -	yes	start if moved	    no
2095  * left relse	  -	yes	start if moved	    no
2096  * middle press	  -	yes	 if not active	    no	    put register
2097  * middle press	  -	yes	 if active	    no	    yank and put
2098  * right press	  -	yes	start or extend	    yes
2099  * right press	  S	yes	no change	    yes	    "#" (2)
2100  * right drag	  -	yes	extend		    no
2101  * right relse	  -	yes	extend		    no
2102  *
2103  * Insert or Replace Mode:
2104  * event	 modi-	position      visual	   change   action
2105  *		 fier	cursor			   window
2106  * left press	  -	yes	(cannot be active)  yes
2107  * left press	  C	yes	(cannot be active)  yes	    "CTRL-O^]" (2)
2108  * left press	  S	yes	(cannot be active)  yes	    "CTRL-O*" (2)
2109  * left drag	  -	yes	start or extend (1) no	    CTRL-O (1)
2110  * left relse	  -	yes	start or extend (1) no	    CTRL-O (1)
2111  * middle press	  -	no	(cannot be active)  no	    put register
2112  * right press	  -	yes	start or extend	    yes	    CTRL-O
2113  * right press	  S	yes	(cannot be active)  yes	    "CTRL-O#" (2)
2114  *
2115  * (1) only if mouse pointer moved since press
2116  * (2) only if click is in same buffer
2117  *
2118  * Return TRUE if start_arrow() should be called for edit mode.
2119  */
2120     int
2121 do_mouse(oap, c, dir, count, fixindent)
2122     oparg_T	*oap;		/* operator argument, can be NULL */
2123     int		c;		/* K_LEFTMOUSE, etc */
2124     int		dir;		/* Direction to 'put' if necessary */
2125     long	count;
2126     int		fixindent;	/* PUT_FIXINDENT if fixing indent necessary */
2127 {
2128     static int	do_always = FALSE;	/* ignore 'mouse' setting next time */
2129     static int	got_click = FALSE;	/* got a click some time back */
2130 
2131     int		which_button;	/* MOUSE_LEFT, _MIDDLE or _RIGHT */
2132     int		is_click;	/* If FALSE it's a drag or release event */
2133     int		is_drag;	/* If TRUE it's a drag event */
2134     int		jump_flags = 0;	/* flags for jump_to_mouse() */
2135     pos_T	start_visual;
2136     int		moved;		/* Has cursor moved? */
2137     int		in_status_line;	/* mouse in status line */
2138 #ifdef FEAT_VERTSPLIT
2139     int		in_sep_line;	/* mouse in vertical separator line */
2140 #endif
2141     int		c1, c2;
2142 #if defined(FEAT_FOLDING)
2143     pos_T	save_cursor;
2144 #endif
2145     win_T	*old_curwin = curwin;
2146 #ifdef FEAT_VISUAL
2147     static pos_T orig_cursor;
2148     colnr_T	leftcol, rightcol;
2149     pos_T	end_visual;
2150     int		diff;
2151     int		old_active = VIsual_active;
2152     int		old_mode = VIsual_mode;
2153 #endif
2154     int		regname;
2155 
2156 #if defined(FEAT_FOLDING)
2157     save_cursor = curwin->w_cursor;
2158 #endif
2159 
2160     /*
2161      * When GUI is active, always recognize mouse events, otherwise:
2162      * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
2163      * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
2164      * - For command line and insert mode 'mouse' is checked before calling
2165      *	 do_mouse().
2166      */
2167     if (do_always)
2168 	do_always = FALSE;
2169     else
2170 #ifdef FEAT_GUI
2171 	if (!gui.in_use)
2172 #endif
2173 	{
2174 #ifdef FEAT_VISUAL
2175 	    if (VIsual_active)
2176 	    {
2177 		if (!mouse_has(MOUSE_VISUAL))
2178 		    return FALSE;
2179 	    }
2180 	    else
2181 #endif
2182 		if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
2183 		return FALSE;
2184 	}
2185 
2186     which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
2187 
2188 #ifdef FEAT_MOUSESHAPE
2189     /* May have stopped dragging the status or separator line.  The pointer is
2190      * most likely still on the status or separator line. */
2191     if (!is_drag && drag_status_line)
2192     {
2193 	drag_status_line = FALSE;
2194 	update_mouseshape(SHAPE_IDX_STATUS);
2195     }
2196 # ifdef FEAT_VERTSPLIT
2197     if (!is_drag && drag_sep_line)
2198     {
2199 	drag_sep_line = FALSE;
2200 	update_mouseshape(SHAPE_IDX_VSEP);
2201     }
2202 # endif
2203 #endif
2204 
2205     /*
2206      * Ignore drag and release events if we didn't get a click.
2207      */
2208     if (is_click)
2209 	got_click = TRUE;
2210     else
2211     {
2212 	if (!got_click)			/* didn't get click, ignore */
2213 	    return FALSE;
2214 	if (!is_drag)			/* release, reset got_click */
2215 	    got_click = FALSE;
2216     }
2217 
2218     /*
2219      * ALT is currently ignored
2220      */
2221     if ((mod_mask & MOD_MASK_ALT))
2222 	return FALSE;
2223 
2224     /*
2225      * CTRL right mouse button does CTRL-T
2226      */
2227     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
2228     {
2229 	if (State & INSERT)
2230 	    stuffcharReadbuff(Ctrl_O);
2231 	if (count > 1)
2232 	    stuffnumReadbuff(count);
2233 	stuffcharReadbuff(Ctrl_T);
2234 	got_click = FALSE;		/* ignore drag&release now */
2235 	return FALSE;
2236     }
2237 
2238     /*
2239      * CTRL only works with left mouse button
2240      */
2241     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
2242 	return FALSE;
2243 
2244     /*
2245      * When a modifier is down, ignore drag and release events, as well as
2246      * multiple clicks and the middle mouse button.
2247      * Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
2248      */
2249     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
2250 	    && (!is_click
2251 		|| (mod_mask & MOD_MASK_MULTI_CLICK)
2252 		|| which_button == MOUSE_MIDDLE)
2253 	    && !((mod_mask & MOD_MASK_SHIFT)
2254 		&& mouse_model_popup()
2255 		&& which_button == MOUSE_LEFT)
2256 	    )
2257 	return FALSE;
2258 
2259     /*
2260      * If the button press was used as the movement command for an operator
2261      * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
2262      * drag/release events.
2263      */
2264     if (!is_click && which_button == MOUSE_MIDDLE)
2265 	return FALSE;
2266 
2267     if (oap != NULL)
2268 	regname = oap->regname;
2269     else
2270 	regname = 0;
2271 
2272     /*
2273      * Middle mouse button does a 'put' of the selected text
2274      */
2275     if (which_button == MOUSE_MIDDLE)
2276     {
2277 	if (State == NORMAL)
2278 	{
2279 	    /*
2280 	     * If an operator was pending, we don't know what the user wanted
2281 	     * to do. Go back to normal mode: Clear the operator and beep().
2282 	     */
2283 	    if (oap != NULL && oap->op_type != OP_NOP)
2284 	    {
2285 		clearopbeep(oap);
2286 		return FALSE;
2287 	    }
2288 
2289 #ifdef FEAT_VISUAL
2290 	    /*
2291 	     * If visual was active, yank the highlighted text and put it
2292 	     * before the mouse pointer position.
2293 	     */
2294 	    if (VIsual_active)
2295 	    {
2296 		stuffcharReadbuff('y');
2297 		stuffcharReadbuff(K_MIDDLEMOUSE);
2298 		do_always = TRUE;	/* ignore 'mouse' setting next time */
2299 		return FALSE;
2300 	    }
2301 #endif
2302 	    /*
2303 	     * The rest is below jump_to_mouse()
2304 	     */
2305 	}
2306 
2307 	else if ((State & INSERT) == 0)
2308 	    return FALSE;
2309 
2310 	/*
2311 	 * Middle click in insert mode doesn't move the mouse, just insert the
2312 	 * contents of a register.  '.' register is special, can't insert that
2313 	 * with do_put().
2314 	 * Also paste at the cursor if the current mode isn't in 'mouse' (only
2315 	 * happens for the GUI).
2316 	 */
2317 	if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
2318 	{
2319 	    if (regname == '.')
2320 		insert_reg(regname, TRUE);
2321 	    else
2322 	    {
2323 #ifdef FEAT_CLIPBOARD
2324 		if (clip_star.available && regname == 0)
2325 		    regname = '*';
2326 #endif
2327 		if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
2328 		    insert_reg(regname, TRUE);
2329 		else
2330 		{
2331 		    do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
2332 
2333 		    /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
2334 		    AppendCharToRedobuff(Ctrl_R);
2335 		    AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
2336 		    AppendCharToRedobuff(regname == 0 ? '"' : regname);
2337 		}
2338 	    }
2339 	    return FALSE;
2340 	}
2341     }
2342 
2343     /* When dragging or button-up stay in the same window. */
2344     if (!is_click)
2345 	jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
2346 
2347     start_visual.lnum = 0;
2348 
2349     /*
2350      * When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
2351      * right button up   -> pop-up menu
2352      * shift-left button -> right button
2353      */
2354     if (mouse_model_popup())
2355     {
2356 	if (which_button == MOUSE_RIGHT
2357 			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
2358 	{
2359 	    /*
2360 	     * NOTE: Ignore right button down and drag mouse events.
2361 	     * Windows only shows the popup menu on the button up event.
2362 	     */
2363 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_KDE)
2364 	    if (!is_click)
2365 		return FALSE;
2366 #endif
2367 #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
2368 	    if (is_click || is_drag)
2369 		return FALSE;
2370 #endif
2371 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE) \
2372 	    || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
2373 	    || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON)
2374 	    if (gui.in_use)
2375 	    {
2376 		jump_flags = 0;
2377 		if (STRCMP(p_mousem, "popup_setpos") == 0)
2378 		{
2379 		    /* First set the cursor position before showing the popup
2380 		     * menu. */
2381 #ifdef FEAT_VISUAL
2382 		    if (VIsual_active)
2383 		    {
2384 			pos_T    m_pos;
2385 
2386 			/*
2387 			 * set MOUSE_MAY_STOP_VIS if we are outside the
2388 			 * selection or the current window (might have false
2389 			 * negative here)
2390 			 */
2391 			if (mouse_row < W_WINROW(curwin)
2392 			     || mouse_row
2393 				      > (W_WINROW(curwin) + curwin->w_height))
2394 			    jump_flags = MOUSE_MAY_STOP_VIS;
2395 			else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
2396 			    jump_flags = MOUSE_MAY_STOP_VIS;
2397 			else
2398 			{
2399 			    if ((lt(curwin->w_cursor, VIsual)
2400 					&& (lt(m_pos, curwin->w_cursor)
2401 					    || lt(VIsual, m_pos)))
2402 				    || (lt(VIsual, curwin->w_cursor)
2403 					&& (lt(m_pos, VIsual)
2404 					    || lt(curwin->w_cursor, m_pos))))
2405 			    {
2406 				jump_flags = MOUSE_MAY_STOP_VIS;
2407 			    }
2408 			    else if (VIsual_mode == Ctrl_V)
2409 			    {
2410 				getvcols(curwin, &curwin->w_cursor, &VIsual,
2411 							 &leftcol, &rightcol);
2412 				getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
2413 				if (m_pos.col < leftcol || m_pos.col > rightcol)
2414 				    jump_flags = MOUSE_MAY_STOP_VIS;
2415 			    }
2416 			}
2417 		    }
2418 		    else
2419 			jump_flags = MOUSE_MAY_STOP_VIS;
2420 #endif
2421 		}
2422 		if (jump_flags)
2423 		{
2424 		    jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
2425 		    update_curbuf(
2426 #ifdef FEAT_VISUAL
2427 			    VIsual_active ? INVERTED :
2428 #endif
2429 			    VALID);
2430 		    setcursor();
2431 		    out_flush();    /* Update before showing popup menu */
2432 		}
2433 # ifdef FEAT_MENU
2434 		gui_show_popupmenu();
2435 # endif
2436 		return (jump_flags & CURSOR_MOVED) != 0;
2437 	    }
2438 	    else
2439 		return FALSE;
2440 #else
2441 	    return FALSE;
2442 #endif
2443 	}
2444 	if (which_button == MOUSE_LEFT && (mod_mask & MOD_MASK_SHIFT))
2445 	{
2446 	    which_button = MOUSE_RIGHT;
2447 	    mod_mask &= ~MOD_MASK_SHIFT;
2448 	}
2449     }
2450 
2451 #ifdef FEAT_VISUAL
2452     if ((State & (NORMAL | INSERT))
2453 			    && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
2454     {
2455 	if (which_button == MOUSE_LEFT)
2456 	{
2457 	    if (is_click)
2458 	    {
2459 		/* stop Visual mode for a left click in a window, but not when
2460 		 * on a status line */
2461 		if (VIsual_active)
2462 		    jump_flags |= MOUSE_MAY_STOP_VIS;
2463 	    }
2464 	    else if (mouse_has(MOUSE_VISUAL))
2465 		jump_flags |= MOUSE_MAY_VIS;
2466 	}
2467 	else if (which_button == MOUSE_RIGHT)
2468 	{
2469 	    if (is_click && VIsual_active)
2470 	    {
2471 		/*
2472 		 * Remember the start and end of visual before moving the
2473 		 * cursor.
2474 		 */
2475 		if (lt(curwin->w_cursor, VIsual))
2476 		{
2477 		    start_visual = curwin->w_cursor;
2478 		    end_visual = VIsual;
2479 		}
2480 		else
2481 		{
2482 		    start_visual = VIsual;
2483 		    end_visual = curwin->w_cursor;
2484 		}
2485 	    }
2486 	    jump_flags |= MOUSE_FOCUS;
2487 	    if (mouse_has(MOUSE_VISUAL))
2488 		jump_flags |= MOUSE_MAY_VIS;
2489 	}
2490     }
2491 #endif
2492 
2493     /*
2494      * If an operator is pending, ignore all drags and releases until the
2495      * next mouse click.
2496      */
2497     if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
2498     {
2499 	got_click = FALSE;
2500 	oap->motion_type = MCHAR;
2501     }
2502 
2503     /* When releasing the button let jump_to_mouse() know. */
2504     if (!is_click && !is_drag)
2505 	jump_flags |= MOUSE_RELEASED;
2506 
2507     /*
2508      * JUMP!
2509      */
2510     jump_flags = jump_to_mouse(jump_flags,
2511 			oap == NULL ? NULL : &(oap->inclusive), which_button);
2512     moved = (jump_flags & CURSOR_MOVED);
2513     in_status_line = (jump_flags & IN_STATUS_LINE);
2514 #ifdef FEAT_VERTSPLIT
2515     in_sep_line = (jump_flags & IN_SEP_LINE);
2516 #endif
2517 
2518 #ifdef FEAT_NETBEANS_INTG
2519     if (usingNetbeans && isNetbeansBuffer(curbuf)
2520 			    && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
2521     {
2522 	int key = KEY2TERMCAP1(c);
2523 
2524 	if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
2525 					       || key == (int)KE_RIGHTRELEASE)
2526 	    netbeans_button_release(which_button);
2527     }
2528 #endif
2529 
2530     /* When jumping to another window, clear a pending operator.  That's a bit
2531      * friendlier than beeping and not jumping to that window. */
2532     if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
2533 	clearop(oap);
2534 
2535 #ifdef FEAT_FOLDING
2536     if (mod_mask == 0
2537 	    && !is_drag
2538 	    && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
2539 	    && which_button == MOUSE_LEFT)
2540     {
2541 	/* open or close a fold at this line */
2542 	if (jump_flags & MOUSE_FOLD_OPEN)
2543 	    openFold(curwin->w_cursor.lnum, 1L);
2544 	else
2545 	    closeFold(curwin->w_cursor.lnum, 1L);
2546 	/* don't move the cursor if still in the same window */
2547 	if (curwin == old_curwin)
2548 	    curwin->w_cursor = save_cursor;
2549     }
2550 #endif
2551 
2552 #if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
2553     if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
2554     {
2555 	clip_modeless(which_button, is_click, is_drag);
2556 	return FALSE;
2557     }
2558 #endif
2559 
2560 #ifdef FEAT_VISUAL
2561     /* Set global flag that we are extending the Visual area with mouse
2562      * dragging; temporarily mimimize 'scrolloff'. */
2563     if (VIsual_active && is_drag && p_so)
2564     {
2565 	/* In the very first line, allow scrolling one line */
2566 	if (mouse_row == 0)
2567 	    mouse_dragging = 2;
2568 	else
2569 	    mouse_dragging = 1;
2570     }
2571 
2572     /* When dragging the mouse above the window, scroll down. */
2573     if (is_drag && mouse_row < 0 && !in_status_line)
2574     {
2575 	scroll_redraw(FALSE, 1L);
2576 	mouse_row = 0;
2577     }
2578 
2579     if (start_visual.lnum)		/* right click in visual mode */
2580     {
2581 	/*
2582 	 * In Visual-block mode, divide the area in four, pick up the corner
2583 	 * that is in the quarter that the cursor is in.
2584 	 */
2585 	if (VIsual_mode == Ctrl_V)
2586 	{
2587 	    getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
2588 	    if (curwin->w_curswant > (leftcol + rightcol) / 2)
2589 		end_visual.col = leftcol;
2590 	    else
2591 		end_visual.col = rightcol;
2592 	    if (curwin->w_cursor.lnum <
2593 				    (start_visual.lnum + end_visual.lnum) / 2)
2594 		end_visual.lnum = end_visual.lnum;
2595 	    else
2596 		end_visual.lnum = start_visual.lnum;
2597 
2598 	    /* move VIsual to the right column */
2599 	    start_visual = curwin->w_cursor;	    /* save the cursor pos */
2600 	    curwin->w_cursor = end_visual;
2601 	    coladvance(end_visual.col);
2602 	    VIsual = curwin->w_cursor;
2603 	    curwin->w_cursor = start_visual;	    /* restore the cursor */
2604 	}
2605 	else
2606 	{
2607 	    /*
2608 	     * If the click is before the start of visual, change the start.
2609 	     * If the click is after the end of visual, change the end.  If
2610 	     * the click is inside the visual, change the closest side.
2611 	     */
2612 	    if (lt(curwin->w_cursor, start_visual))
2613 		VIsual = end_visual;
2614 	    else if (lt(end_visual, curwin->w_cursor))
2615 		VIsual = start_visual;
2616 	    else
2617 	    {
2618 		/* In the same line, compare column number */
2619 		if (end_visual.lnum == start_visual.lnum)
2620 		{
2621 		    if (curwin->w_cursor.col - start_visual.col >
2622 				    end_visual.col - curwin->w_cursor.col)
2623 			VIsual = start_visual;
2624 		    else
2625 			VIsual = end_visual;
2626 		}
2627 
2628 		/* In different lines, compare line number */
2629 		else
2630 		{
2631 		    diff = (curwin->w_cursor.lnum - start_visual.lnum) -
2632 				(end_visual.lnum - curwin->w_cursor.lnum);
2633 
2634 		    if (diff > 0)		/* closest to end */
2635 			VIsual = start_visual;
2636 		    else if (diff < 0)	/* closest to start */
2637 			VIsual = end_visual;
2638 		    else			/* in the middle line */
2639 		    {
2640 			if (curwin->w_cursor.col <
2641 					(start_visual.col + end_visual.col) / 2)
2642 			    VIsual = end_visual;
2643 			else
2644 			    VIsual = start_visual;
2645 		    }
2646 		}
2647 	    }
2648 	}
2649     }
2650     /*
2651      * If Visual mode started in insert mode, execute "CTRL-O"
2652      */
2653     else if ((State & INSERT) && VIsual_active)
2654 	stuffcharReadbuff(Ctrl_O);
2655 #endif
2656 
2657     /*
2658      * Middle mouse click: Put text before cursor.
2659      */
2660     if (which_button == MOUSE_MIDDLE)
2661     {
2662 #ifdef FEAT_CLIPBOARD
2663 	if (clip_star.available && regname == 0)
2664 	    regname = '*';
2665 #endif
2666 	if (yank_register_mline(regname))
2667 	{
2668 	    if (mouse_past_bottom)
2669 		dir = FORWARD;
2670 	}
2671 	else if (mouse_past_eol)
2672 	    dir = FORWARD;
2673 
2674 	if (fixindent)
2675 	{
2676 	    c1 = (dir == BACKWARD) ? '[' : ']';
2677 	    c2 = 'p';
2678 	}
2679 	else
2680 	{
2681 	    c1 = (dir == FORWARD) ? 'p' : 'P';
2682 	    c2 = NUL;
2683 	}
2684 	prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
2685 
2686 	/*
2687 	 * Remember where the paste started, so in edit() Insstart can be set
2688 	 * to this position
2689 	 */
2690 	if (restart_edit != 0)
2691 	    where_paste_started = curwin->w_cursor;
2692 	do_put(regname, dir, count, fixindent | PUT_CURSEND);
2693     }
2694 
2695 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
2696     /*
2697      * Ctrl-Mouse click or double click in a quickfix window jumps to the
2698      * error under the mouse pointer.
2699      */
2700     else if (((mod_mask & MOD_MASK_CTRL)
2701 		|| (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
2702 	    && bt_quickfix(curbuf))
2703     {
2704 	if (State & INSERT)
2705 	    stuffcharReadbuff(Ctrl_O);
2706 	stuffReadbuff((char_u *)":.cc\n");
2707 	got_click = FALSE;		/* ignore drag&release now */
2708     }
2709 #endif
2710 
2711     /*
2712      * Ctrl-Mouse click (or double click in a help window) jumps to the tag
2713      * under the mouse pointer.
2714      */
2715     else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
2716 		     && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
2717     {
2718 	if (State & INSERT)
2719 	    stuffcharReadbuff(Ctrl_O);
2720 	stuffcharReadbuff(Ctrl_RSB);
2721 	got_click = FALSE;		/* ignore drag&release now */
2722     }
2723 
2724     /*
2725      * Shift-Mouse click searches for the next occurrence of the word under
2726      * the mouse pointer
2727      */
2728     else if ((mod_mask & MOD_MASK_SHIFT))
2729     {
2730 	if (State & INSERT
2731 #ifdef FEAT_VISUAL
2732 		|| (VIsual_active && VIsual_select)
2733 #endif
2734 		)
2735 	    stuffcharReadbuff(Ctrl_O);
2736 	if (which_button == MOUSE_LEFT)
2737 	    stuffcharReadbuff('*');
2738 	else	/* MOUSE_RIGHT */
2739 	    stuffcharReadbuff('#');
2740     }
2741 
2742     /* Handle double clicks, unless on status line */
2743     else if (in_status_line)
2744     {
2745 #ifdef FEAT_MOUSESHAPE
2746 	if ((is_drag || is_click) && !drag_status_line)
2747 	{
2748 	    drag_status_line = TRUE;
2749 	    update_mouseshape(-1);
2750 	}
2751 #endif
2752     }
2753 #ifdef FEAT_VERTSPLIT
2754     else if (in_sep_line)
2755     {
2756 # ifdef FEAT_MOUSESHAPE
2757 	if ((is_drag || is_click) && !drag_sep_line)
2758 	{
2759 	    drag_sep_line = TRUE;
2760 	    update_mouseshape(-1);
2761 	}
2762 # endif
2763     }
2764 #endif
2765 #ifdef FEAT_VISUAL
2766     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
2767 	     && mouse_has(MOUSE_VISUAL))
2768     {
2769 	if (is_click || !VIsual_active)
2770 	{
2771 	    if (VIsual_active)
2772 		orig_cursor = VIsual;
2773 	    else
2774 	    {
2775 		check_visual_highlight();
2776 		VIsual = curwin->w_cursor;
2777 		orig_cursor = VIsual;
2778 		VIsual_active = TRUE;
2779 		VIsual_reselect = TRUE;
2780 		/* start Select mode if 'selectmode' contains "mouse" */
2781 		may_start_select('o');
2782 		setmouse();
2783 	    }
2784 	    if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
2785 		VIsual_mode = 'v';
2786 	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
2787 		VIsual_mode = 'V';
2788 	    else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
2789 		VIsual_mode = Ctrl_V;
2790 #ifdef FEAT_CLIPBOARD
2791 	    /* Make sure the clipboard gets updated.  Needed because start and
2792 	     * end may still be the same, and the selection needs to be owned */
2793 	    clip_star.vmode = NUL;
2794 #endif
2795 	}
2796 	/*
2797 	 * A double click selects a word or a block.
2798 	 */
2799 	if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
2800 	{
2801 	    pos_T	*pos = NULL;
2802 
2803 	    if (is_click)
2804 	    {
2805 		/* If the character under the cursor (skipping white space) is
2806 		 * not a word character, try finding a match and select a (),
2807 		 * {}, [], #if/#endif, etc. block. */
2808 		end_visual = curwin->w_cursor;
2809 		while (vim_iswhite(gchar_pos(&end_visual)))
2810 		    inc(&end_visual);
2811 		if (oap != NULL)
2812 		    oap->motion_type = MCHAR;
2813 		if (oap != NULL
2814 			&& VIsual_mode == 'v'
2815 			&& !vim_iswordc(gchar_pos(&end_visual))
2816 			&& equalpos(curwin->w_cursor, VIsual)
2817 			&& (pos = findmatch(oap, NUL)) != NULL)
2818 		{
2819 		    curwin->w_cursor = *pos;
2820 		    if (oap->motion_type == MLINE)
2821 			VIsual_mode = 'V';
2822 		    else if (*p_sel == 'e')
2823 		    {
2824 			if (lt(curwin->w_cursor, VIsual))
2825 			    ++VIsual.col;
2826 			else
2827 			    ++curwin->w_cursor.col;
2828 		    }
2829 		}
2830 	    }
2831 
2832 	    if (pos == NULL && (is_click || is_drag))
2833 	    {
2834 		/* When not found a match or when dragging: extend to include
2835 		 * a word. */
2836 		if (lt(curwin->w_cursor, orig_cursor))
2837 		{
2838 		    find_start_of_word(&curwin->w_cursor);
2839 		    find_end_of_word(&VIsual);
2840 		}
2841 		else
2842 		{
2843 		    find_start_of_word(&VIsual);
2844 		    if (*p_sel == 'e' && *ml_get_cursor() != NUL)
2845 #ifdef FEAT_MBYTE
2846 			curwin->w_cursor.col +=
2847 					 (*mb_ptr2len_check)(ml_get_cursor());
2848 #else
2849 			++curwin->w_cursor.col;
2850 #endif
2851 		    find_end_of_word(&curwin->w_cursor);
2852 		}
2853 	    }
2854 	    curwin->w_set_curswant = TRUE;
2855 	}
2856 	if (is_click)
2857 	    redraw_curbuf_later(INVERTED);	/* update the inversion */
2858     }
2859     else if (VIsual_active && !old_active)
2860 	VIsual_mode = 'v';
2861 
2862     /* If Visual mode changed show it later. */
2863     if (p_smd && (VIsual_active != old_active || VIsual_mode != old_mode))
2864 	redraw_cmdline = TRUE;
2865 #endif
2866 
2867     return moved;
2868 }
2869 
2870 #ifdef FEAT_VISUAL
2871 /*
2872  * Move "pos" back to the start of the word it's in.
2873  */
2874     static void
2875 find_start_of_word(pos)
2876     pos_T	*pos;
2877 {
2878     char_u	*line;
2879     int		cclass;
2880     int		col;
2881 
2882     line = ml_get(pos->lnum);
2883     cclass = get_mouse_class(line + pos->col);
2884 
2885     while (pos->col > 0)
2886     {
2887 	col = pos->col - 1;
2888 #ifdef FEAT_MBYTE
2889 	col -= (*mb_head_off)(line, line + col);
2890 #endif
2891 	if (get_mouse_class(line + col) != cclass)
2892 	    break;
2893 	pos->col = col;
2894     }
2895 }
2896 
2897 /*
2898  * Move "pos" forward to the end of the word it's in.
2899  * When 'selection' is "exclusive", the position is just after the word.
2900  */
2901     static void
2902 find_end_of_word(pos)
2903     pos_T	*pos;
2904 {
2905     char_u	*line;
2906     int		cclass;
2907     int		col;
2908 
2909     line = ml_get(pos->lnum);
2910     if (*p_sel == 'e' && pos->col > 0)
2911     {
2912 	--pos->col;
2913 #ifdef FEAT_MBYTE
2914 	pos->col -= (*mb_head_off)(line, line + pos->col);
2915 #endif
2916     }
2917     cclass = get_mouse_class(line + pos->col);
2918     while (line[pos->col] != NUL)
2919     {
2920 #ifdef FEAT_MBYTE
2921 	col = pos->col + (*mb_ptr2len_check)(line + pos->col);
2922 #else
2923 	col = pos->col + 1;
2924 #endif
2925 	if (get_mouse_class(line + col) != cclass)
2926 	{
2927 	    if (*p_sel == 'e')
2928 		pos->col = col;
2929 	    break;
2930 	}
2931 	pos->col = col;
2932     }
2933 }
2934 
2935 /*
2936  * Get class of a character for selection: same class means same word.
2937  * 0: blank
2938  * 1: punctuation groups
2939  * 2: normal word character
2940  * >2: multi-byte word character.
2941  */
2942     static int
2943 get_mouse_class(p)
2944     char_u	*p;
2945 {
2946     int		c;
2947 
2948 #ifdef FEAT_MBYTE
2949     if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
2950 	return mb_get_class(p);
2951 #endif
2952 
2953     c = *p;
2954     if (c == ' ' || c == '\t')
2955 	return 0;
2956 
2957     if (vim_iswordc(c))
2958 	return 2;
2959 
2960     /*
2961      * There are a few special cases where we want certain combinations of
2962      * characters to be considered as a single word.  These are things like
2963      * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
2964      * character is in it's own class.
2965      */
2966     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
2967 	return 1;
2968     return c;
2969 }
2970 #endif /* FEAT_VISUAL */
2971 #endif /* FEAT_MOUSE */
2972 
2973 #if defined(FEAT_VISUAL) || defined(PROTO)
2974 /*
2975  * Check if  highlighting for visual mode is possible, give a warning message
2976  * if not.
2977  */
2978     void
2979 check_visual_highlight()
2980 {
2981     static int	    did_check = FALSE;
2982 
2983     if (full_screen)
2984     {
2985 	if (!did_check && hl_attr(HLF_V) == 0)
2986 	    MSG(_("Warning: terminal cannot highlight"));
2987 	did_check = TRUE;
2988     }
2989 }
2990 
2991 /*
2992  * End visual mode.
2993  * This function should ALWAYS be called to end Visual mode, except from
2994  * do_pending_operator().
2995  */
2996     void
2997 end_visual_mode()
2998 {
2999 #ifdef FEAT_CLIPBOARD
3000     /*
3001      * If we are using the clipboard, then remember what was selected in case
3002      * we need to paste it somewhere while we still own the selection.
3003      * Only do this when the clipboard is already owned.  Don't want to grab
3004      * the selection when hitting ESC.
3005      */
3006     if (clip_star.available && clip_star.owned)
3007 	clip_auto_select();
3008 #endif
3009 
3010     VIsual_active = FALSE;
3011 #ifdef FEAT_MOUSE
3012     setmouse();
3013     mouse_dragging = 0;
3014 #endif
3015 
3016     /* Save the current VIsual area for '< and '> marks, and "gv" */
3017     curbuf->b_visual_mode = VIsual_mode;
3018 #ifdef FEAT_EVAL
3019     curbuf->b_visual_mode_eval = VIsual_mode;
3020 #endif
3021     curbuf->b_visual_start = VIsual;
3022     curbuf->b_visual_end = curwin->w_cursor;
3023     curbuf->b_visual_curswant = curwin->w_curswant;
3024 #ifdef FEAT_VIRTUALEDIT
3025     if (!virtual_active())
3026 	curwin->w_cursor.coladd = 0;
3027 #endif
3028 
3029     if (p_smd)
3030 	clear_cmdline = TRUE;		/* unshow visual mode later */
3031 #ifdef FEAT_CMDL_INFO
3032     else
3033 	clear_showcmd();
3034 #endif
3035 
3036     /* Don't leave the cursor past the end of the line */
3037     if (curwin->w_cursor.col > 0 && *ml_get_cursor() == NUL)
3038 	--curwin->w_cursor.col;
3039 }
3040 
3041 /*
3042  * Reset VIsual_active and VIsual_reselect.
3043  */
3044     void
3045 reset_VIsual_and_resel()
3046 {
3047     if (VIsual_active)
3048     {
3049 	end_visual_mode();
3050 	redraw_curbuf_later(INVERTED);	/* delete the inversion later */
3051     }
3052     VIsual_reselect = FALSE;
3053 }
3054 
3055 /*
3056  * Reset VIsual_active and VIsual_reselect if it's set.
3057  */
3058     void
3059 reset_VIsual()
3060 {
3061     if (VIsual_active)
3062     {
3063 	end_visual_mode();
3064 	redraw_curbuf_later(INVERTED);	/* delete the inversion later */
3065 	VIsual_reselect = FALSE;
3066     }
3067 }
3068 #endif /* FEAT_VISUAL */
3069 
3070 #if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3071 static int find_is_eval_item __ARGS((char_u *ptr, int *colp, int *nbp, int dir));
3072 
3073 /*
3074  * Check for a balloon-eval special item to include when searching for an
3075  * identifier.  When "dir" is BACKWARD "ptr[-1]" must be valid!
3076  * Returns TRUE if the character at "*ptr" should be included.
3077  * "dir" is FORWARD or BACKWARD, the direction of searching.
3078  * "*colp" is in/decremented if "ptr[-dir]" should also be included.
3079  * "bnp" points to a counter for square brackets.
3080  */
3081     static int
3082 find_is_eval_item(ptr, colp, bnp, dir)
3083     char_u	*ptr;
3084     int		*colp;
3085     int		*bnp;
3086     int		dir;
3087 {
3088     /* Accept everything inside []. */
3089     if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD))
3090 	++*bnp;
3091     if (*bnp > 0)
3092     {
3093 	if ((*ptr == '[' && dir == BACKWARD) || (*ptr == ']' && dir == FORWARD))
3094 	    --*bnp;
3095 	return TRUE;
3096     }
3097 
3098     /* skip over "s.var" */
3099     if (*ptr == '.')
3100 	return TRUE;
3101 
3102     /* two-character item: s->var */
3103     if (ptr[dir == BACKWARD ? 0 : 1] == '>'
3104 	    && ptr[dir == BACKWARD ? -1 : 0] == '-')
3105     {
3106 	*colp += dir;
3107 	return TRUE;
3108     }
3109     return FALSE;
3110 }
3111 #endif
3112 
3113 /*
3114  * Find the identifier under or to the right of the cursor.
3115  * "find_type" can have one of three values:
3116  * FIND_IDENT:   find an identifier (keyword)
3117  * FIND_STRING:  find any non-white string
3118  * FIND_IDENT + FIND_STRING: find any non-white string, identifier preferred.
3119  *
3120  * There are three steps:
3121  * 1. Search forward for the start of an identifier/string.  Doesn't move if
3122  *    already on one.
3123  * 2. Search backward for the start of this identifier/string.
3124  *    This doesn't match the real Vi but I like it a little better and it
3125  *    shouldn't bother anyone.
3126  * 3. Search forward to the end of this identifier/string.
3127  *    When FIND_IDENT isn't defined, we backup until a blank.
3128  *
3129  * Returns the length of the string, or zero if no string is found.
3130  * If a string is found, a pointer to the string is put in "*string".  This
3131  * string is not always NUL terminated.
3132  */
3133     int
3134 find_ident_under_cursor(string, find_type)
3135     char_u	**string;
3136     int		find_type;
3137 {
3138     return find_ident_at_pos(curwin, curwin->w_cursor.lnum,
3139 				     curwin->w_cursor.col, string, find_type);
3140 }
3141 
3142 /*
3143  * Like find_ident_under_cursor(), but for any window and any position.
3144  * However: Uses 'iskeyword' from the current window!.
3145  */
3146     int
3147 find_ident_at_pos(wp, lnum, startcol, string, find_type)
3148     win_T	*wp;
3149     linenr_T	lnum;
3150     colnr_T	startcol;
3151     char_u	**string;
3152     int		find_type;
3153 {
3154     char_u	*ptr;
3155     int		col = 0;	    /* init to shut up GCC */
3156     int		i;
3157 #ifdef FEAT_MBYTE
3158     int		this_class = 0;
3159     int		prev_class;
3160     int		prevcol;
3161 #endif
3162 #if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3163     int		bn = 0;	    /* bracket nesting */
3164 #endif
3165 
3166     /*
3167      * if i == 0: try to find an identifier
3168      * if i == 1: try to find any non-white string
3169      */
3170     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
3171     for (i = (find_type & FIND_IDENT) ? 0 : 1;	i < 2; ++i)
3172     {
3173 	/*
3174 	 * 1. skip to start of identifier/string
3175 	 */
3176 	col = startcol;
3177 #ifdef FEAT_MBYTE
3178 	if (has_mbyte)
3179 	{
3180 	    while (ptr[col] != NUL)
3181 	    {
3182 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3183 		/* Stop at a ']' to evaluate "a[x]". */
3184 		if ((find_type & FIND_EVAL) && ptr[col] == ']')
3185 		    break;
3186 # endif
3187 		this_class = mb_get_class(ptr + col);
3188 		if (this_class != 0 && (i == 1 || this_class != 1))
3189 		    break;
3190 		col += (*mb_ptr2len_check)(ptr + col);
3191 	    }
3192 	}
3193 	else
3194 #endif
3195 	    while (ptr[col] != NUL
3196 		    && (i == 0 ? !vim_iswordc(ptr[col]) : vim_iswhite(ptr[col]))
3197 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3198 		    && (!(find_type & FIND_EVAL) || ptr[col] != ']')
3199 # endif
3200 		    )
3201 		++col;
3202 
3203 #if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3204 	/* When starting on a ']' count it, so that we include the '['. */
3205 	bn = ptr[col] == ']';
3206 #endif
3207 
3208 	/*
3209 	 * 2. Back up to start of identifier/string.
3210 	 */
3211 #ifdef FEAT_MBYTE
3212 	if (has_mbyte)
3213 	{
3214 	    /* Remember class of character under cursor. */
3215 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3216 	    if ((find_type & FIND_EVAL) && ptr[col] == ']')
3217 		this_class = mb_get_class((char_u *)"a");
3218 	    else
3219 # endif
3220 		this_class = mb_get_class(ptr + col);
3221 	    while (col > 0)
3222 	    {
3223 		prevcol = col - 1 - (*mb_head_off)(ptr, ptr + col - 1);
3224 		prev_class = mb_get_class(ptr + prevcol);
3225 		if (this_class != prev_class
3226 			&& (i == 0
3227 			    || prev_class == 0
3228 			    || (find_type & FIND_IDENT))
3229 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3230 			&& (!(find_type & FIND_EVAL)
3231 			    || prevcol == 0
3232 			    || !find_is_eval_item(ptr + prevcol, &prevcol,
3233 							       &bn, BACKWARD))
3234 # endif
3235 			)
3236 		    break;
3237 		col = prevcol;
3238 	    }
3239 
3240 	    /* If we don't want just any old string, or we've found an
3241 	     * identifier, stop searching. */
3242 	    if (this_class > 2)
3243 		this_class = 2;
3244 	    if (!(find_type & FIND_STRING) || this_class == 2)
3245 		break;
3246 	}
3247 	else
3248 #endif
3249 	{
3250 	    while (col > 0
3251 		    && ((i == 0
3252 			    ? vim_iswordc(ptr[col - 1])
3253 			    : (!vim_iswhite(ptr[col - 1])
3254 				&& (!(find_type & FIND_IDENT)
3255 				    || !vim_iswordc(ptr[col - 1]))))
3256 #if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3257 			|| ((find_type & FIND_EVAL)
3258 			    && col > 1
3259 			    && find_is_eval_item(ptr + col - 1, &col,
3260 							       &bn, BACKWARD))
3261 #endif
3262 			))
3263 		--col;
3264 
3265 	    /* If we don't want just any old string, or we've found an
3266 	     * identifier, stop searching. */
3267 	    if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
3268 		break;
3269 	}
3270     }
3271 
3272     if (ptr[col] == NUL || (i == 0 && (
3273 #ifdef FEAT_MBYTE
3274 		has_mbyte ? this_class != 2 :
3275 #endif
3276 		!vim_iswordc(ptr[col]))))
3277     {
3278 	/*
3279 	 * didn't find an identifier or string
3280 	 */
3281 	if (find_type & FIND_STRING)
3282 	    EMSG(_("E348: No string under cursor"));
3283 	else
3284 	    EMSG(_("E349: No identifier under cursor"));
3285 	return 0;
3286     }
3287     ptr += col;
3288     *string = ptr;
3289 
3290     /*
3291      * 3. Find the end if the identifier/string.
3292      */
3293 #if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3294     bn = 0;
3295     startcol -= col;
3296 #endif
3297     col = 0;
3298 #ifdef FEAT_MBYTE
3299     if (has_mbyte)
3300     {
3301 	/* Search for point of changing multibyte character class. */
3302 	this_class = mb_get_class(ptr);
3303 	while (ptr[col] != NUL
3304 		&& ((i == 0 ? mb_get_class(ptr + col) == this_class
3305 			    : mb_get_class(ptr + col) != 0)
3306 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3307 		    || ((find_type & FIND_EVAL)
3308 			&& col <= (int)startcol
3309 			&& find_is_eval_item(ptr + col, &col, &bn, FORWARD))
3310 # endif
3311 		))
3312 	    col += (*mb_ptr2len_check)(ptr + col);
3313     }
3314     else
3315 #endif
3316 	while ((i == 0 ? vim_iswordc(ptr[col])
3317 		       : (ptr[col] != NUL && !vim_iswhite(ptr[col])))
3318 # if defined(FEAT_NETBEANS_INTG) && defined(FEAT_BEVAL)
3319 		    || ((find_type & FIND_EVAL)
3320 			&& col <= (int)startcol
3321 			&& find_is_eval_item(ptr + col, &col, &bn, FORWARD))
3322 # endif
3323 		)
3324 	{
3325 	    ++col;
3326 	}
3327 
3328     return col;
3329 }
3330 
3331 /*
3332  * Prepare for redo of a normal command.
3333  */
3334     static void
3335 prep_redo_cmd(cap)
3336     cmdarg_T  *cap;
3337 {
3338     prep_redo(cap->oap->regname, cap->count0,
3339 				     NUL, cap->cmdchar, NUL, NUL, cap->nchar);
3340 }
3341 
3342 /*
3343  * Prepare for redo of any command.
3344  * Note that only the last argument can be a multi-byte char.
3345  */
3346     static void
3347 prep_redo(regname, num, cmd1, cmd2, cmd3, cmd4, cmd5)
3348     int	    regname;
3349     long    num;
3350     int	    cmd1;
3351     int	    cmd2;
3352     int	    cmd3;
3353     int	    cmd4;
3354     int	    cmd5;
3355 {
3356     ResetRedobuff();
3357     if (regname != 0)	/* yank from specified buffer */
3358     {
3359 	AppendCharToRedobuff('"');
3360 	AppendCharToRedobuff(regname);
3361     }
3362     if (num)
3363 	AppendNumberToRedobuff(num);
3364 
3365     if (cmd1 != NUL)
3366 	AppendCharToRedobuff(cmd1);
3367     if (cmd2 != NUL)
3368 	AppendCharToRedobuff(cmd2);
3369     if (cmd3 != NUL)
3370 	AppendCharToRedobuff(cmd3);
3371     if (cmd4 != NUL)
3372 	AppendCharToRedobuff(cmd4);
3373     if (cmd5 != NUL)
3374 	AppendCharToRedobuff(cmd5);
3375 }
3376 
3377 /*
3378  * check for operator active and clear it
3379  *
3380  * return TRUE if operator was active
3381  */
3382     static int
3383 checkclearop(oap)
3384     oparg_T	*oap;
3385 {
3386     if (oap->op_type == OP_NOP)
3387 	return FALSE;
3388     clearopbeep(oap);
3389     return TRUE;
3390 }
3391 
3392 /*
3393  * check for operator or Visual active and clear it
3394  *
3395  * return TRUE if operator was active
3396  */
3397     static int
3398 checkclearopq(oap)
3399     oparg_T	*oap;
3400 {
3401     if (oap->op_type == OP_NOP
3402 #ifdef FEAT_VISUAL
3403 	    && !VIsual_active
3404 #endif
3405 	    )
3406 	return FALSE;
3407     clearopbeep(oap);
3408     return TRUE;
3409 }
3410 
3411     static void
3412 clearop(oap)
3413     oparg_T	*oap;
3414 {
3415     oap->op_type = OP_NOP;
3416     oap->regname = 0;
3417     oap->motion_force = NUL;
3418     oap->use_reg_one = FALSE;
3419 }
3420 
3421     static void
3422 clearopbeep(oap)
3423     oparg_T	*oap;
3424 {
3425     clearop(oap);
3426     beep_flush();
3427 }
3428 
3429 #ifdef FEAT_VISUAL
3430 /*
3431  * Remove the shift modifier from a special key.
3432  */
3433     static void
3434 unshift_special(cap)
3435     cmdarg_T	*cap;
3436 {
3437     switch (cap->cmdchar)
3438     {
3439 	case K_S_RIGHT:	cap->cmdchar = K_RIGHT; break;
3440 	case K_S_LEFT:	cap->cmdchar = K_LEFT; break;
3441 	case K_S_UP:	cap->cmdchar = K_UP; break;
3442 	case K_S_DOWN:	cap->cmdchar = K_DOWN; break;
3443 	case K_S_HOME:	cap->cmdchar = K_HOME; break;
3444 	case K_S_END:	cap->cmdchar = K_END; break;
3445     }
3446     cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask);
3447 }
3448 #endif
3449 
3450 #if defined(FEAT_CMDL_INFO) || defined(PROTO)
3451 /*
3452  * Routines for displaying a partly typed command
3453  */
3454 
3455 #ifdef FEAT_VISUAL	/* need room for size of Visual area */
3456 # define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
3457 #else
3458 # define SHOWCMD_BUFLEN SHOWCMD_COLS + 1
3459 #endif
3460 static char_u	showcmd_buf[SHOWCMD_BUFLEN];
3461 static char_u	old_showcmd_buf[SHOWCMD_BUFLEN];  /* For push_showcmd() */
3462 static int	showcmd_is_clear = TRUE;
3463 static int	showcmd_visual = FALSE;
3464 
3465 static void display_showcmd __ARGS((void));
3466 
3467     void
3468 clear_showcmd()
3469 {
3470     if (!p_sc)
3471 	return;
3472 
3473 #ifdef FEAT_VISUAL
3474     if (VIsual_active && !char_avail())
3475     {
3476 	int		i = lt(VIsual, curwin->w_cursor);
3477 	long		lines;
3478 	colnr_T		leftcol, rightcol;
3479 	linenr_T	top, bot;
3480 
3481 	/* Show the size of the Visual area. */
3482 	if (i)
3483 	{
3484 	    top = VIsual.lnum;
3485 	    bot = curwin->w_cursor.lnum;
3486 	}
3487 	else
3488 	{
3489 	    top = curwin->w_cursor.lnum;
3490 	    bot = VIsual.lnum;
3491 	}
3492 # ifdef FEAT_FOLDING
3493 	/* Include closed folds as a whole. */
3494 	hasFolding(top, &top, NULL);
3495 	hasFolding(bot, NULL, &bot);
3496 # endif
3497 	lines = bot - top + 1;
3498 
3499 	if (VIsual_mode == Ctrl_V)
3500 	{
3501 	    getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
3502 	    sprintf((char *)showcmd_buf, "%ldx%ld", lines,
3503 					      (long)(rightcol - leftcol + 1));
3504 	}
3505 	else if (VIsual_mode == 'V' || VIsual.lnum != curwin->w_cursor.lnum)
3506 	    sprintf((char *)showcmd_buf, "%ld", lines);
3507 	else
3508 	    sprintf((char *)showcmd_buf, "%ld", (long)(i
3509 		    ? curwin->w_cursor.col - VIsual.col
3510 		    : VIsual.col - curwin->w_cursor.col) + (*p_sel != 'e'));
3511 	showcmd_buf[SHOWCMD_COLS] = NUL;	/* truncate */
3512 	showcmd_visual = TRUE;
3513     }
3514     else
3515 #endif
3516     {
3517 	showcmd_buf[0] = NUL;
3518 	showcmd_visual = FALSE;
3519 
3520 	/* Don't actually display something if there is nothing to clear. */
3521 	if (showcmd_is_clear)
3522 	    return;
3523     }
3524 
3525     display_showcmd();
3526 }
3527 
3528 /*
3529  * Add 'c' to string of shown command chars.
3530  * Return TRUE if output has been written (and setcursor() has been called).
3531  */
3532     int
3533 add_to_showcmd(c)
3534     int		c;
3535 {
3536     char_u	*p;
3537     int		old_len;
3538     int		extra_len;
3539     int		overflow;
3540 #if defined(FEAT_MOUSE)
3541     int		i;
3542     static int	ignore[] =
3543     {
3544 #ifdef FEAT_GUI
3545 	K_VER_SCROLLBAR, K_HOR_SCROLLBAR,
3546 	K_LEFTMOUSE_NM, K_LEFTRELEASE_NM,
3547 #endif
3548 	K_IGNORE,
3549 	K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE,
3550 	K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
3551 	K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
3552 	K_MOUSEDOWN, K_MOUSEUP,
3553 	K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
3554 	0
3555     };
3556 #endif
3557 
3558     if (!p_sc)
3559 	return FALSE;
3560 
3561     if (showcmd_visual)
3562     {
3563 	showcmd_buf[0] = NUL;
3564 	showcmd_visual = FALSE;
3565     }
3566 
3567 #if defined(FEAT_MOUSE)
3568     /* Ignore keys that are scrollbar updates and mouse clicks */
3569     if (IS_SPECIAL(c))
3570 	for (i = 0; ignore[i] != 0; ++i)
3571 	    if (ignore[i] == c)
3572 		return FALSE;
3573 #endif
3574 
3575     p = transchar(c);
3576     old_len = (int)STRLEN(showcmd_buf);
3577     extra_len = (int)STRLEN(p);
3578     overflow = old_len + extra_len - SHOWCMD_COLS;
3579     if (overflow > 0)
3580 	STRCPY(showcmd_buf, showcmd_buf + overflow);
3581     STRCAT(showcmd_buf, p);
3582 
3583     if (char_avail())
3584 	return FALSE;
3585 
3586     display_showcmd();
3587 
3588     return TRUE;
3589 }
3590 
3591     void
3592 add_to_showcmd_c(c)
3593     int		c;
3594 {
3595     if (!add_to_showcmd(c))
3596 	setcursor();
3597 }
3598 
3599 /*
3600  * Delete 'len' characters from the end of the shown command.
3601  */
3602     static void
3603 del_from_showcmd(len)
3604     int	    len;
3605 {
3606     int	    old_len;
3607 
3608     if (!p_sc)
3609 	return;
3610 
3611     old_len = (int)STRLEN(showcmd_buf);
3612     if (len > old_len)
3613 	len = old_len;
3614     showcmd_buf[old_len - len] = NUL;
3615 
3616     if (!char_avail())
3617 	display_showcmd();
3618 }
3619 
3620 /*
3621  * push_showcmd() and pop_showcmd() are used when waiting for the user to type
3622  * something and there is a partial mapping.
3623  */
3624     void
3625 push_showcmd()
3626 {
3627     if (p_sc)
3628 	STRCPY(old_showcmd_buf, showcmd_buf);
3629 }
3630 
3631     void
3632 pop_showcmd()
3633 {
3634     if (!p_sc)
3635 	return;
3636 
3637     STRCPY(showcmd_buf, old_showcmd_buf);
3638 
3639     display_showcmd();
3640 }
3641 
3642     static void
3643 display_showcmd()
3644 {
3645     int	    len;
3646 
3647     cursor_off();
3648 
3649     len = (int)STRLEN(showcmd_buf);
3650     if (len == 0)
3651 	showcmd_is_clear = TRUE;
3652     else
3653     {
3654 	screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0);
3655 	showcmd_is_clear = FALSE;
3656     }
3657 
3658     /*
3659      * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
3660      */
3661     screen_puts((char_u *)"          " + len, (int)Rows - 1, sc_col + len, 0);
3662 
3663     setcursor();	    /* put cursor back where it belongs */
3664 }
3665 #endif
3666 
3667 #ifdef FEAT_SCROLLBIND
3668 /*
3669  * When "check" is FALSE, prepare for commands that scroll the window.
3670  * When "check" is TRUE, take care of scroll-binding after the window has
3671  * scrolled.  Called from normal_cmd() and edit().
3672  */
3673     void
3674 do_check_scrollbind(check)
3675     int		check;
3676 {
3677     static win_T	*old_curwin = NULL;
3678     static linenr_T	old_topline = 0;
3679 #ifdef FEAT_DIFF
3680     static int		old_topfill = 0;
3681 #endif
3682     static buf_T	*old_buf = NULL;
3683     static colnr_T	old_leftcol = 0;
3684 
3685     if (check && curwin->w_p_scb)
3686     {
3687 	/* If a ":syncbind" command was just used, don't scroll, only reset
3688 	 * the values. */
3689 	if (did_syncbind)
3690 	    did_syncbind = FALSE;
3691 	else if (curwin == old_curwin)
3692 	{
3693 	    /*
3694 	     * Synchronize other windows, as necessary according to
3695 	     * 'scrollbind'.  Don't do this after an ":edit" command, except
3696 	     * when 'diff' is set.
3697 	     */
3698 	    if ((curwin->w_buffer == old_buf
3699 #ifdef FEAT_DIFF
3700 			|| curwin->w_p_diff
3701 #endif
3702 		)
3703 		&& (curwin->w_topline != old_topline
3704 #ifdef FEAT_DIFF
3705 			|| curwin->w_topfill != old_topfill
3706 #endif
3707 			|| curwin->w_leftcol != old_leftcol))
3708 	    {
3709 		check_scrollbind(curwin->w_topline - old_topline,
3710 			(long)(curwin->w_leftcol - old_leftcol));
3711 	    }
3712 	}
3713 	else if (vim_strchr(p_sbo, 'j')) /* jump flag set in 'scrollopt' */
3714 	{
3715 	    /*
3716 	     * When switching between windows, make sure that the relative
3717 	     * vertical offset is valid for the new window.  The relative
3718 	     * offset is invalid whenever another 'scrollbind' window has
3719 	     * scrolled to a point that would force the current window to
3720 	     * scroll past the beginning or end of its buffer.  When the
3721 	     * resync is performed, some of the other 'scrollbind' windows may
3722 	     * need to jump so that the current window's relative position is
3723 	     * visible on-screen.
3724 	     */
3725 	    check_scrollbind(curwin->w_topline - curwin->w_scbind_pos, 0L);
3726 	}
3727 	curwin->w_scbind_pos = curwin->w_topline;
3728     }
3729 
3730     old_curwin = curwin;
3731     old_topline = curwin->w_topline;
3732 #ifdef FEAT_DIFF
3733     old_topfill = curwin->w_topfill;
3734 #endif
3735     old_buf = curwin->w_buffer;
3736     old_leftcol = curwin->w_leftcol;
3737 }
3738 
3739 /*
3740  * Synchronize any windows that have "scrollbind" set, based on the
3741  * number of rows by which the current window has changed
3742  * (1998-11-02 16:21:01  R. Edward Ralston <[email protected]>)
3743  */
3744     void
3745 check_scrollbind(topline_diff, leftcol_diff)
3746     linenr_T	topline_diff;
3747     long	leftcol_diff;
3748 {
3749     int		want_ver;
3750     int		want_hor;
3751     win_T	*old_curwin = curwin;
3752     buf_T	*old_curbuf = curbuf;
3753 #ifdef FEAT_VISUAL
3754     int		old_VIsual_select = VIsual_select;
3755     int		old_VIsual_active = VIsual_active;
3756 #endif
3757     colnr_T	tgt_leftcol = curwin->w_leftcol;
3758     long	topline;
3759     long	y;
3760 
3761     /*
3762      * check 'scrollopt' string for vertical and horizontal scroll options
3763      */
3764     want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0);
3765 #ifdef FEAT_DIFF
3766     want_ver |= old_curwin->w_p_diff;
3767 #endif
3768     want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 0));
3769 
3770     /*
3771      * loop through the scrollbound windows and scroll accordingly
3772      */
3773 #ifdef FEAT_VISUAL
3774     VIsual_select = VIsual_active = 0;
3775 #endif
3776     for (curwin = firstwin; curwin; curwin = curwin->w_next)
3777     {
3778 	curbuf = curwin->w_buffer;
3779 	/* skip original window  and windows with 'noscrollbind' */
3780 	if (curwin != old_curwin && curwin->w_p_scb)
3781 	{
3782 	    /*
3783 	     * do the vertical scroll
3784 	     */
3785 	    if (want_ver)
3786 	    {
3787 #ifdef FEAT_DIFF
3788 		if (old_curwin->w_p_diff && curwin->w_p_diff)
3789 		{
3790 		    diff_set_topline(old_curwin, curwin);
3791 		}
3792 		else
3793 #endif
3794 		{
3795 		    curwin->w_scbind_pos += topline_diff;
3796 		    topline = curwin->w_scbind_pos;
3797 		    if (topline > curbuf->b_ml.ml_line_count)
3798 			topline = curbuf->b_ml.ml_line_count;
3799 		    if (topline < 1)
3800 			topline = 1;
3801 
3802 		    y = topline - curwin->w_topline;
3803 		    if (y > 0)
3804 			scrollup(y, FALSE);
3805 		    else
3806 			scrolldown(-y, FALSE);
3807 		}
3808 
3809 		redraw_later(VALID);
3810 		cursor_correct();
3811 #ifdef FEAT_WINDOWS
3812 		curwin->w_redr_status = TRUE;
3813 #endif
3814 	    }
3815 
3816 	    /*
3817 	     * do the horizontal scroll
3818 	     */
3819 	    if (want_hor && curwin->w_leftcol != tgt_leftcol)
3820 	    {
3821 		curwin->w_leftcol = tgt_leftcol;
3822 		leftcol_changed();
3823 	    }
3824 	}
3825     }
3826 
3827     /*
3828      * reset current-window
3829      */
3830 #ifdef FEAT_VISUAL
3831     VIsual_select = old_VIsual_select;
3832     VIsual_active = old_VIsual_active;
3833 #endif
3834     curwin = old_curwin;
3835     curbuf = old_curbuf;
3836 }
3837 #endif /* #ifdef FEAT_SCROLLBIND */
3838 
3839 /*
3840  * Command character that's ignored.
3841  * Used for CTRL-Q and CTRL-S to avoid problems with terminals that use
3842  * xon/xoff
3843  */
3844 /*ARGSUSED */
3845     static void
3846 nv_ignore(cap)
3847     cmdarg_T	*cap;
3848 {
3849 }
3850 
3851 /*
3852  * Command character doesn't exist.
3853  */
3854     static void
3855 nv_error(cap)
3856     cmdarg_T	*cap;
3857 {
3858     clearopbeep(cap->oap);
3859 }
3860 
3861 /*
3862  * <Help> and <F1> commands.
3863  */
3864     static void
3865 nv_help(cap)
3866     cmdarg_T	*cap;
3867 {
3868     if (!checkclearopq(cap->oap))
3869 	ex_help(NULL);
3870 }
3871 
3872 /*
3873  * CTRL-A and CTRL-X: Add or subtract from letter or number under cursor.
3874  */
3875     static void
3876 nv_addsub(cap)
3877     cmdarg_T	*cap;
3878 {
3879     if (!checkclearopq(cap->oap)
3880 	    && do_addsub((int)cap->cmdchar, cap->count1) == OK)
3881 	prep_redo_cmd(cap);
3882 }
3883 
3884 /*
3885  * CTRL-F, CTRL-B, etc: Scroll page up or down.
3886  */
3887     static void
3888 nv_page(cap)
3889     cmdarg_T	*cap;
3890 {
3891     if (!checkclearop(cap->oap))
3892 	(void)onepage(cap->arg, cap->count1);
3893 }
3894 
3895 /*
3896  * Implementation of "gd" and "gD" command.
3897  */
3898     static void
3899 nv_gd(oap, nchar)
3900     oparg_T   *oap;
3901     int	    nchar;
3902 {
3903     int		len;
3904     char_u	*pat;
3905     pos_T	old_pos;
3906     int		t;
3907     int		save_p_ws;
3908     int		save_p_scs;
3909     char_u	*ptr;
3910 
3911     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
3912 					       (pat = alloc(len + 5)) == NULL)
3913     {
3914 	clearopbeep(oap);
3915 	return;
3916     }
3917     sprintf((char *)pat, vim_iswordp(ptr) ? "\\<%.*s\\>" : "%.*s", len, ptr);
3918     old_pos = curwin->w_cursor;
3919     save_p_ws = p_ws;
3920     save_p_scs = p_scs;
3921     p_ws = FALSE;	/* don't wrap around end of file now */
3922     p_scs = FALSE;	/* don't switch ignorecase off now */
3923 
3924     /*
3925      * With "gD" go to line 1.
3926      * With "gd" Search back for the start of the current function, then go
3927      * back until a blank line.  If this fails go to line 1.
3928      */
3929     if (nchar == 'D' || !findpar(oap, BACKWARD, 1L, '{', FALSE))
3930     {
3931 	setpcmark();			/* Set in findpar() otherwise */
3932 	curwin->w_cursor.lnum = 1;
3933     }
3934     else
3935     {
3936 	while (curwin->w_cursor.lnum > 1 && *skipwhite(ml_get_curline()) != NUL)
3937 	    --curwin->w_cursor.lnum;
3938     }
3939     curwin->w_cursor.col = 0;
3940 
3941     /* Search forward for the identifier, ignore comment lines. */
3942     while ((t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD, pat, 1L, 0,
3943 							     RE_LAST)) != FAIL
3944 #ifdef FEAT_COMMENTS
3945 	    && get_leader_len(ml_get_curline(), NULL, FALSE) > 0
3946 #endif
3947 	    && old_pos.lnum > curwin->w_cursor.lnum)
3948     {
3949 	/* Ignore this line, continue at start of next line. */
3950 	++curwin->w_cursor.lnum;
3951 	curwin->w_cursor.col = 0;
3952     }
3953     if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
3954     {
3955 	clearopbeep(oap);
3956 	curwin->w_cursor = old_pos;
3957     }
3958     else
3959     {
3960 	curwin->w_set_curswant = TRUE;
3961 #ifdef FEAT_FOLDING
3962 	if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP)
3963 	    foldOpenCursor();
3964 #endif
3965 	/* "n" searches forward now */
3966 	reset_search_dir();
3967     }
3968 
3969     vim_free(pat);
3970     p_ws = save_p_ws;
3971     p_scs = save_p_scs;
3972 }
3973 
3974 /*
3975  * Move 'dist' lines in direction 'dir', counting lines by *screen*
3976  * lines rather than lines in the file.
3977  * 'dist' must be positive.
3978  *
3979  * Return OK if able to move cursor, FAIL otherwise.
3980  */
3981     static int
3982 nv_screengo(oap, dir, dist)
3983     oparg_T	*oap;
3984     int		dir;
3985     long	dist;
3986 {
3987     int		linelen = linetabsize(ml_get_curline());
3988     int		retval = OK;
3989     int		atend = FALSE;
3990     int		n;
3991     int		col_off1;	/* margin offset for first screen line */
3992     int		col_off2;	/* margin offset for wrapped screen line */
3993     int		width1;		/* text width for first screen line */
3994     int		width2;		/* test width for wrapped screen line */
3995 
3996     oap->motion_type = MCHAR;
3997     oap->inclusive = FALSE;
3998 
3999     col_off1 = curwin_col_off();
4000     col_off2 = col_off1 - curwin_col_off2();
4001     width1 = W_WIDTH(curwin) - col_off1;
4002     width2 = W_WIDTH(curwin) - col_off2;
4003 
4004 #ifdef FEAT_VERTSPLIT
4005     if (curwin->w_width != 0)
4006     {
4007 #endif
4008       /*
4009        * Instead of sticking at the last character of the buffer line we
4010        * try to stick in the last column of the screen.
4011        */
4012       if (curwin->w_curswant == MAXCOL)
4013       {
4014 	atend = TRUE;
4015 	validate_virtcol();
4016 	if (width1 <= 0)
4017 	    curwin->w_curswant = 0;
4018 	else
4019 	{
4020 	    curwin->w_curswant = width1 - 1;
4021 	    if (curwin->w_virtcol > curwin->w_curswant)
4022 		curwin->w_curswant += ((curwin->w_virtcol
4023 			     - curwin->w_curswant - 1) / width2 + 1) * width2;
4024 	}
4025       }
4026       else
4027       {
4028 	if (linelen > width1)
4029 	    n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
4030 	else
4031 	    n = width1;
4032 	if (curwin->w_curswant > (colnr_T)n + 1)
4033 	    curwin->w_curswant -= ((curwin->w_curswant - n) / width2 + 1)
4034 								     * width2;
4035       }
4036 
4037       while (dist--)
4038       {
4039 	if (dir == BACKWARD)
4040 	{
4041 	    if ((long)curwin->w_curswant >= width2)
4042 		/* move back within line */
4043 		curwin->w_curswant -= width2;
4044 	    else
4045 	    {
4046 		/* to previous line */
4047 		if (curwin->w_cursor.lnum == 1)
4048 		{
4049 		    retval = FAIL;
4050 		    break;
4051 		}
4052 		--curwin->w_cursor.lnum;
4053 #ifdef FEAT_FOLDING
4054 		/* Move to the start of a closed fold.  Don't do that when
4055 		 * 'foldopen' contains "all": it will open in a moment. */
4056 		if (!(fdo_flags & FDO_ALL))
4057 		    (void)hasFolding(curwin->w_cursor.lnum,
4058 						&curwin->w_cursor.lnum, NULL);
4059 #endif
4060 		linelen = linetabsize(ml_get_curline());
4061 		if (linelen > width1)
4062 		    curwin->w_curswant += (((linelen - width1 - 1) / width2)
4063 								+ 1) * width2;
4064 	    }
4065 	}
4066 	else /* dir == FORWARD */
4067 	{
4068 	    if (linelen > width1)
4069 		n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
4070 	    else
4071 		n = width1;
4072 	    if (curwin->w_curswant + width2 < (colnr_T)n)
4073 		/* move forward within line */
4074 		curwin->w_curswant += width2;
4075 	    else
4076 	    {
4077 		/* to next line */
4078 #ifdef FEAT_FOLDING
4079 		/* Move to the end of a closed fold. */
4080 		(void)hasFolding(curwin->w_cursor.lnum, NULL,
4081 						      &curwin->w_cursor.lnum);
4082 #endif
4083 		if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
4084 		{
4085 		    retval = FAIL;
4086 		    break;
4087 		}
4088 		curwin->w_cursor.lnum++;
4089 		curwin->w_curswant %= width2;
4090 	    }
4091 	}
4092       }
4093 #ifdef FEAT_VERTSPLIT
4094     }
4095 #endif
4096 
4097     coladvance(curwin->w_curswant);
4098 
4099 #if defined(FEAT_LINEBREAK) || defined(FEAT_MBYTE)
4100     if (curwin->w_cursor.col > 0 && curwin->w_p_wrap)
4101     {
4102 	/*
4103 	 * Check for landing on a character that got split at the end of the
4104 	 * last line.  We want to advance a screenline, not end up in the same
4105 	 * screenline or move two screenlines.
4106 	 */
4107 	validate_virtcol();
4108 	if (curwin->w_virtcol > curwin->w_curswant
4109 		&& (curwin->w_curswant < (colnr_T)width1
4110 		    ? (curwin->w_curswant > (colnr_T)width1 / 2)
4111 		    : ((curwin->w_curswant - width1) % width2
4112 						      > (colnr_T)width2 / 2)))
4113 	    --curwin->w_cursor.col;
4114     }
4115 #endif
4116 
4117     if (atend)
4118 	curwin->w_curswant = MAXCOL;	    /* stick in the last column */
4119 
4120     return retval;
4121 }
4122 
4123 #ifdef FEAT_MOUSE
4124 /*
4125  * Mouse scroll wheel: Default action is to scroll three lines, or one page
4126  * when Shift or Ctrl is used.
4127  * K_MOUSEUP (cap->arg == TRUE) or K_MOUSEDOWN (cap->arg == FALSE)
4128  */
4129     static void
4130 nv_mousescroll(cap)
4131     cmdarg_T	*cap;
4132 {
4133 # if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
4134     win_T *old_curwin;
4135 
4136     old_curwin = curwin;
4137 
4138     /* Currently we only get the mouse coordinates in the GUI. */
4139     if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
4140     {
4141 	int row, col;
4142 
4143 	row = mouse_row;
4144 	col = mouse_col;
4145 
4146 	/* find the window at the pointer coordinates */
4147 	curwin = mouse_find_win(&row, &col);
4148 	curbuf = curwin->w_buffer;
4149     }
4150 # endif
4151 
4152     if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
4153     {
4154 	(void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
4155     }
4156     else
4157     {
4158 	cap->count1 = 3;
4159 	cap->count0 = 3;
4160 	nv_scroll_line(cap);
4161     }
4162 
4163 # if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
4164     curwin->w_redr_status = TRUE;
4165 
4166     curwin = old_curwin;
4167     curbuf = curwin->w_buffer;
4168 # endif
4169 }
4170 
4171 /*
4172  * Mouse clicks and drags.
4173  */
4174     static void
4175 nv_mouse(cap)
4176     cmdarg_T	*cap;
4177 {
4178     (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
4179 }
4180 #endif
4181 
4182 /*
4183  * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
4184  * cap->arg must be TRUE for CTRL-E.
4185  */
4186     static void
4187 nv_scroll_line(cap)
4188     cmdarg_T	*cap;
4189 {
4190     if (!checkclearop(cap->oap))
4191 	scroll_redraw(cap->arg, cap->count1);
4192 }
4193 
4194 /*
4195  * Scroll "count" lines up or down, and redraw.
4196  */
4197     void
4198 scroll_redraw(up, count)
4199     int		up;
4200     long	count;
4201 {
4202     linenr_T	prev_topline = curwin->w_topline;
4203 #ifdef FEAT_DIFF
4204     int		prev_topfill = curwin->w_topfill;
4205 #endif
4206     linenr_T	prev_lnum = curwin->w_cursor.lnum;
4207 
4208     if (up)
4209 	scrollup(count, TRUE);
4210     else
4211 	scrolldown(count, TRUE);
4212     if (p_so)
4213     {
4214 	/* Adjust the cursor position for 'scrolloff'.  Mark w_topline as
4215 	 * valid, otherwise the screen jumps back at the end of the file. */
4216 	cursor_correct();
4217 	check_cursor_moved(curwin);
4218 	curwin->w_valid |= VALID_TOPLINE;
4219 
4220 	/* If moved back to where we were, at least move the cursor, otherwise
4221 	 * we get stuck at one position.  Don't move the cursor up if the
4222 	 * first line of the buffer is already on the screen */
4223 	while (curwin->w_topline == prev_topline
4224 #ifdef FEAT_DIFF
4225 		&& curwin->w_topfill == prev_topfill
4226 #endif
4227 		)
4228 	{
4229 	    if (up)
4230 	    {
4231 		if (curwin->w_cursor.lnum > prev_lnum
4232 			|| cursor_down(1L, FALSE) == FAIL)
4233 		    break;
4234 	    }
4235 	    else
4236 	    {
4237 		if (curwin->w_cursor.lnum < prev_lnum
4238 			|| prev_topline == 1L
4239 			|| cursor_up(1L, FALSE) == FAIL)
4240 		    break;
4241 	    }
4242 	    /* Mark w_topline as valid, otherwise the screen jumps back at the
4243 	     * end of the file. */
4244 	    check_cursor_moved(curwin);
4245 	    curwin->w_valid |= VALID_TOPLINE;
4246 	}
4247     }
4248     if (curwin->w_cursor.lnum != prev_lnum)
4249 	coladvance(curwin->w_curswant);
4250     redraw_later(VALID);
4251 }
4252 
4253 /*
4254  * Commands that start with "z".
4255  */
4256     static void
4257 nv_zet(cap)
4258     cmdarg_T  *cap;
4259 {
4260     long	n;
4261     colnr_T	col;
4262     int		nchar = cap->nchar;
4263 #ifdef FEAT_FOLDING
4264     long	old_fdl = curwin->w_p_fdl;
4265     int		old_fen = curwin->w_p_fen;
4266 #endif
4267 
4268     if (VIM_ISDIGIT(nchar))
4269     {
4270 	/*
4271 	 * "z123{nchar}": edit the count before obtaining {nchar}
4272 	 */
4273 	if (checkclearop(cap->oap))
4274 	    return;
4275 	n = nchar - '0';
4276 	for (;;)
4277 	{
4278 #ifdef USE_ON_FLY_SCROLL
4279 	    dont_scroll = TRUE;		/* disallow scrolling here */
4280 #endif
4281 	    ++no_mapping;
4282 	    ++allow_keys;   /* no mapping for nchar, but allow key codes */
4283 	    nchar = safe_vgetc();
4284 #ifdef FEAT_LANGMAP
4285 	    LANGMAP_ADJUST(nchar, TRUE);
4286 #endif
4287 	    --no_mapping;
4288 	    --allow_keys;
4289 #ifdef FEAT_CMDL_INFO
4290 	    (void)add_to_showcmd(nchar);
4291 #endif
4292 	    if (nchar == K_DEL || nchar == K_KDEL)
4293 		n /= 10;
4294 	    else if (VIM_ISDIGIT(nchar))
4295 		n = n * 10 + (nchar - '0');
4296 	    else if (nchar == CAR)
4297 	    {
4298 #ifdef FEAT_GUI
4299 		need_mouse_correct = TRUE;
4300 #endif
4301 		win_setheight((int)n);
4302 		break;
4303 	    }
4304 	    else if (nchar == 'l'
4305 		    || nchar == 'h'
4306 		    || nchar == K_LEFT
4307 		    || nchar == K_RIGHT)
4308 	    {
4309 		cap->count1 = n ? n * cap->count1 : cap->count1;
4310 		goto dozet;
4311 	    }
4312 	    else
4313 	    {
4314 		clearopbeep(cap->oap);
4315 		break;
4316 	    }
4317 	}
4318 	cap->oap->op_type = OP_NOP;
4319 	return;
4320     }
4321 
4322 dozet:
4323     if (
4324 #ifdef FEAT_FOLDING
4325 	    /* "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
4326 	     * and "zC" only in Visual mode.  "zj" and "zk" are motion
4327 	     * commands. */
4328 	    cap->nchar != 'f' && cap->nchar != 'F'
4329 	    && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar))
4330 	    && cap->nchar != 'j' && cap->nchar != 'k'
4331 	    &&
4332 #endif
4333 	    checkclearop(cap->oap))
4334 	return;
4335 
4336     /*
4337      * For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb":
4338      * If line number given, set cursor.
4339      */
4340     if ((vim_strchr((char_u *)"+\r\nt.z^-b", nchar) != NULL)
4341 	    && cap->count0
4342 	    && cap->count0 != curwin->w_cursor.lnum)
4343     {
4344 	setpcmark();
4345 	if (cap->count0 > curbuf->b_ml.ml_line_count)
4346 	    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4347 	else
4348 	    curwin->w_cursor.lnum = cap->count0;
4349 	check_cursor_col();
4350     }
4351 
4352     switch (nchar)
4353     {
4354 		/* "z+", "z<CR>" and "zt": put cursor at top of screen */
4355     case '+':
4356 		if (cap->count0 == 0)
4357 		{
4358 		    /* No count given: put cursor at the line below screen */
4359 		    validate_botline();	/* make sure w_botline is valid */
4360 		    if (curwin->w_botline > curbuf->b_ml.ml_line_count)
4361 			curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4362 		    else
4363 			curwin->w_cursor.lnum = curwin->w_botline;
4364 		}
4365 		/* FALLTHROUGH */
4366     case NL:
4367     case CAR:
4368     case K_KENTER:
4369 		beginline(BL_WHITE | BL_FIX);
4370 		/* FALLTHROUGH */
4371 
4372     case 't':	scroll_cursor_top(0, TRUE);
4373 		redraw_later(VALID);
4374 		break;
4375 
4376 		/* "z." and "zz": put cursor in middle of screen */
4377     case '.':	beginline(BL_WHITE | BL_FIX);
4378 		/* FALLTHROUGH */
4379 
4380     case 'z':	scroll_cursor_halfway(TRUE);
4381 		redraw_later(VALID);
4382 		break;
4383 
4384 		/* "z^", "z-" and "zb": put cursor at bottom of screen */
4385     case '^':	/* Strange Vi behavior: <count>z^ finds line at top of window
4386 		 * when <count> is at bottom of window, and puts that one at
4387 		 * bottom of window. */
4388 		if (cap->count0 != 0)
4389 		{
4390 		    scroll_cursor_bot(0, TRUE);
4391 		    curwin->w_cursor.lnum = curwin->w_topline;
4392 		}
4393 		else if (curwin->w_topline == 1)
4394 		    curwin->w_cursor.lnum = 1;
4395 		else
4396 		    curwin->w_cursor.lnum = curwin->w_topline - 1;
4397 		/* FALLTHROUGH */
4398     case '-':
4399 		beginline(BL_WHITE | BL_FIX);
4400 		/* FALLTHROUGH */
4401 
4402     case 'b':	scroll_cursor_bot(0, TRUE);
4403 		redraw_later(VALID);
4404 		break;
4405 
4406 		/* "zH" - scroll screen right half-page */
4407     case 'H':
4408 		cap->count1 *= W_WIDTH(curwin) / 2;
4409 		/* FALLTHROUGH */
4410 
4411 		/* "zh" - scroll screen to the right */
4412     case 'h':
4413     case K_LEFT:
4414 		if (!curwin->w_p_wrap)
4415 		{
4416 		    if ((colnr_T)cap->count1 > curwin->w_leftcol)
4417 			curwin->w_leftcol = 0;
4418 		    else
4419 			curwin->w_leftcol -= (colnr_T)cap->count1;
4420 		    leftcol_changed();
4421 		}
4422 		break;
4423 
4424 		/* "zL" - scroll screen left half-page */
4425     case 'L':	cap->count1 *= W_WIDTH(curwin) / 2;
4426 		/* FALLTHROUGH */
4427 
4428 		/* "zl" - scroll screen to the left */
4429     case 'l':
4430     case K_RIGHT:
4431 		if (!curwin->w_p_wrap)
4432 		{
4433 		    /* scroll the window left */
4434 		    curwin->w_leftcol += (colnr_T)cap->count1;
4435 		    leftcol_changed();
4436 		}
4437 		break;
4438 
4439 		/* "zs" - scroll screen, cursor at the start */
4440     case 's':	if (!curwin->w_p_wrap)
4441 		{
4442 #ifdef FEAT_FOLDING
4443 		    if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
4444 			col = 0;	/* like the cursor is in col 0 */
4445 		    else
4446 #endif
4447 		    getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
4448 		    if ((long)col > p_siso)
4449 			col -= p_siso;
4450 		    else
4451 			col = 0;
4452 		    if (curwin->w_leftcol != col)
4453 		    {
4454 			curwin->w_leftcol = col;
4455 			redraw_later(NOT_VALID);
4456 		    }
4457 		}
4458 		break;
4459 
4460 		/* "ze" - scroll screen, cursor at the end */
4461     case 'e':	if (!curwin->w_p_wrap)
4462 		{
4463 #ifdef FEAT_FOLDING
4464 		    if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
4465 			col = 0;	/* like the cursor is in col 0 */
4466 		    else
4467 #endif
4468 		    getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
4469 		    n = W_WIDTH(curwin) - curwin_col_off();
4470 		    if ((long)col + p_siso < n)
4471 			col = 0;
4472 		    else
4473 			col = col + p_siso - n + 1;
4474 		    if (curwin->w_leftcol != col)
4475 		    {
4476 			curwin->w_leftcol = col;
4477 			redraw_later(NOT_VALID);
4478 		    }
4479 		}
4480 		break;
4481 
4482 #ifdef FEAT_FOLDING
4483 		/* "zF": create fold command */
4484 		/* "zf": create fold operator */
4485     case 'F':
4486     case 'f':   if (foldManualAllowed(TRUE))
4487 		{
4488 		    cap->nchar = 'f';
4489 		    nv_operator(cap);
4490 		    curwin->w_p_fen = TRUE;
4491 
4492 		    /* "zF" is like "zfzf" */
4493 		    if (nchar == 'F' && cap->oap->op_type == OP_FOLD)
4494 		    {
4495 			nv_operator(cap);
4496 			finish_op = TRUE;
4497 		    }
4498 		}
4499 		else
4500 		    clearopbeep(cap->oap);
4501 		break;
4502 
4503 		/* "zd": delete fold at cursor */
4504 		/* "zD": delete fold at cursor recursively */
4505     case 'd':
4506     case 'D':	if (foldManualAllowed(FALSE))
4507 		{
4508 		    if (VIsual_active)
4509 			nv_operator(cap);
4510 		    else
4511 			deleteFold(curwin->w_cursor.lnum,
4512 				  curwin->w_cursor.lnum, nchar == 'D', FALSE);
4513 		}
4514 		break;
4515 
4516 		/* "zE": erease all folds */
4517     case 'E':	if (foldmethodIsManual(curwin))
4518 		{
4519 		    clearFolding(curwin);
4520 		    changed_window_setting();
4521 		}
4522 		else if (foldmethodIsMarker(curwin))
4523 		    deleteFold((linenr_T)1, curbuf->b_ml.ml_line_count,
4524 								 TRUE, FALSE);
4525 		else
4526 		    EMSG(_("E352: Cannot erase folds with current 'foldmethod'"));
4527 		break;
4528 
4529 		/* "zn": fold none: reset 'foldenable' */
4530     case 'n':	curwin->w_p_fen = FALSE;
4531 		break;
4532 
4533 		/* "zN": fold Normal: set 'foldenable' */
4534     case 'N':	curwin->w_p_fen = TRUE;
4535 		break;
4536 
4537 		/* "zi": invert folding: toggle 'foldenable' */
4538     case 'i':	curwin->w_p_fen = !curwin->w_p_fen;
4539 		break;
4540 
4541 		/* "za": open closed fold or close open fold at cursor */
4542     case 'a':	if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
4543 		    openFold(curwin->w_cursor.lnum, cap->count1);
4544 		else
4545 		{
4546 		    closeFold(curwin->w_cursor.lnum, cap->count1);
4547 		    curwin->w_p_fen = TRUE;
4548 		}
4549 		break;
4550 
4551 		/* "zA": open fold at cursor recursively */
4552     case 'A':	if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
4553 		    openFoldRecurse(curwin->w_cursor.lnum);
4554 		else
4555 		{
4556 		    closeFoldRecurse(curwin->w_cursor.lnum);
4557 		    curwin->w_p_fen = TRUE;
4558 		}
4559 		break;
4560 
4561 		/* "zo": open fold at cursor or Visual area */
4562     case 'o':	if (VIsual_active)
4563 		    nv_operator(cap);
4564 		else
4565 		    openFold(curwin->w_cursor.lnum, cap->count1);
4566 		break;
4567 
4568 		/* "zO": open fold recursively */
4569     case 'O':	if (VIsual_active)
4570 		    nv_operator(cap);
4571 		else
4572 		    openFoldRecurse(curwin->w_cursor.lnum);
4573 		break;
4574 
4575 		/* "zc": close fold at cursor or Visual area */
4576     case 'c':	if (VIsual_active)
4577 		    nv_operator(cap);
4578 		else
4579 		    closeFold(curwin->w_cursor.lnum, cap->count1);
4580 		curwin->w_p_fen = TRUE;
4581 		break;
4582 
4583 		/* "zC": close fold recursively */
4584     case 'C':	if (VIsual_active)
4585 		    nv_operator(cap);
4586 		else
4587 		    closeFoldRecurse(curwin->w_cursor.lnum);
4588 		curwin->w_p_fen = TRUE;
4589 		break;
4590 
4591 		/* "zv": open folds at the cursor */
4592     case 'v':	foldOpenCursor();
4593 		break;
4594 
4595 		/* "zx": re-apply 'foldlevel' and open folds at the cursor */
4596     case 'x':	curwin->w_p_fen = TRUE;
4597 		newFoldLevel();		/* update right now */
4598 		foldOpenCursor();
4599 		break;
4600 
4601 		/* "zX": undo manual opens/closes, re-apply 'foldlevel' */
4602     case 'X':	curwin->w_p_fen = TRUE;
4603 		old_fdl = -1;		/* force an update */
4604 		break;
4605 
4606 		/* "zm": fold more */
4607     case 'm':	if (curwin->w_p_fdl > 0)
4608 		    --curwin->w_p_fdl;
4609 		old_fdl = -1;		/* force an update */
4610 		curwin->w_p_fen = TRUE;
4611 		break;
4612 
4613 		/* "zM": close all folds */
4614     case 'M':	curwin->w_p_fdl = 0;
4615 		old_fdl = -1;		/* force an update */
4616 		curwin->w_p_fen = TRUE;
4617 		break;
4618 
4619 		/* "zr": reduce folding */
4620     case 'r':	++curwin->w_p_fdl;
4621 		break;
4622 
4623 		/* "zR": open all folds */
4624     case 'R':	curwin->w_p_fdl = getDeepestNesting();
4625 		old_fdl = -1;		/* force an update */
4626 		break;
4627 
4628     case 'j':	/* "zj" move to next fold downwards */
4629     case 'k':	/* "zk" move to next fold upwards */
4630 		if (foldMoveTo(TRUE, nchar == 'j' ? FORWARD : BACKWARD,
4631 							  cap->count1) == FAIL)
4632 		    clearopbeep(cap->oap);
4633 		break;
4634 
4635 #endif /* FEAT_FOLDING */
4636 
4637     default:	clearopbeep(cap->oap);
4638     }
4639 
4640 #ifdef FEAT_FOLDING
4641     /* Redraw when 'foldenable' changed */
4642     if (old_fen != curwin->w_p_fen)
4643     {
4644 # ifdef FEAT_DIFF
4645 	win_T	    *wp;
4646 
4647 	if (foldmethodIsDiff(curwin) && curwin->w_p_scb)
4648 	{
4649 	    /* Adjust 'foldenable' in diff-synced windows. */
4650 	    FOR_ALL_WINDOWS(wp)
4651 	    {
4652 		if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb)
4653 		{
4654 		    wp->w_p_fen = curwin->w_p_fen;
4655 		    changed_window_setting_win(wp);
4656 		}
4657 	    }
4658 	}
4659 # endif
4660 	changed_window_setting();
4661     }
4662 
4663     /* Redraw when 'foldlevel' changed. */
4664     if (old_fdl != curwin->w_p_fdl)
4665 	newFoldLevel();
4666 #endif
4667 }
4668 
4669 #ifdef FEAT_GUI
4670 /*
4671  * Vertical scrollbar movement.
4672  */
4673     static void
4674 nv_ver_scrollbar(cap)
4675     cmdarg_T	*cap;
4676 {
4677     if (cap->oap->op_type != OP_NOP)
4678 	clearopbeep(cap->oap);
4679 
4680     /* Even if an operator was pending, we still want to scroll */
4681     gui_do_scroll();
4682 }
4683 
4684 /*
4685  * Horizontal scrollbar movement.
4686  */
4687     static void
4688 nv_hor_scrollbar(cap)
4689     cmdarg_T	*cap;
4690 {
4691     if (cap->oap->op_type != OP_NOP)
4692 	clearopbeep(cap->oap);
4693 
4694     /* Even if an operator was pending, we still want to scroll */
4695     gui_do_horiz_scroll();
4696 }
4697 #endif
4698 
4699 /*
4700  * "Q" command.
4701  */
4702     static void
4703 nv_exmode(cap)
4704     cmdarg_T	*cap;
4705 {
4706     /*
4707      * Ignore 'Q' in Visual mode, just give a beep.
4708      */
4709 #ifdef FEAT_VISUAL
4710     if (VIsual_active)
4711 	vim_beep();
4712     else
4713 #endif
4714 	if (!checkclearop(cap->oap))
4715 	do_exmode(FALSE);
4716 }
4717 
4718 /*
4719  * Handle a ":" command.
4720  */
4721     static void
4722 nv_colon(cap)
4723     cmdarg_T  *cap;
4724 {
4725     int	    old_p_im;
4726 
4727 #ifdef FEAT_VISUAL
4728     if (VIsual_active)
4729 	nv_operator(cap);
4730     else
4731 #endif
4732     {
4733 	if (cap->oap->op_type != OP_NOP)
4734 	{
4735 	    /* Using ":" as a movement is characterwise exclusive. */
4736 	    cap->oap->motion_type = MCHAR;
4737 	    cap->oap->inclusive = FALSE;
4738 	}
4739 	else if (cap->count0)
4740 	{
4741 	    /* translate "count:" into ":.,.+(count - 1)" */
4742 	    stuffcharReadbuff('.');
4743 	    if (cap->count0 > 1)
4744 	    {
4745 		stuffReadbuff((char_u *)",.+");
4746 		stuffnumReadbuff((long)cap->count0 - 1L);
4747 	    }
4748 	}
4749 
4750 	/* When typing, don't type below an old message */
4751 	if (KeyTyped)
4752 	    compute_cmdrow();
4753 
4754 	old_p_im = p_im;
4755 
4756 	/* get a command line and execute it */
4757 	do_cmdline(NULL, getexline, NULL,
4758 			    cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
4759 
4760 	/* If 'insertmode' changed, enter or exit Insert mode */
4761 	if (p_im != old_p_im)
4762 	{
4763 	    if (p_im)
4764 		restart_edit = 'i';
4765 	    else
4766 		restart_edit = 0;
4767 	}
4768 
4769 	/* The start of the operator may have become invalid by the Ex
4770 	 * command. */
4771 	if (cap->oap->op_type != OP_NOP
4772 		&& (cap->oap->start.lnum > curbuf->b_ml.ml_line_count
4773 		    || cap->oap->start.col >
4774 					 STRLEN(ml_get(cap->oap->start.lnum))))
4775 	    clearopbeep(cap->oap);
4776     }
4777 }
4778 
4779 /*
4780  * Handle CTRL-G command.
4781  */
4782     static void
4783 nv_ctrlg(cap)
4784     cmdarg_T *cap;
4785 {
4786 #ifdef FEAT_VISUAL
4787     if (VIsual_active)	/* toggle Selection/Visual mode */
4788     {
4789 	VIsual_select = !VIsual_select;
4790 	showmode();
4791     }
4792     else
4793 #endif
4794 	if (!checkclearop(cap->oap))
4795 	/* print full name if count given or :cd used */
4796 	fileinfo((int)cap->count0, FALSE, TRUE);
4797 }
4798 
4799 /*
4800  * Handle CTRL-H <Backspace> command.
4801  */
4802     static void
4803 nv_ctrlh(cap)
4804     cmdarg_T *cap;
4805 {
4806 #ifdef FEAT_VISUAL
4807     if (VIsual_active && VIsual_select)
4808     {
4809 	cap->cmdchar = 'x';	/* BS key behaves like 'x' in Select mode */
4810 	v_visop(cap);
4811     }
4812     else
4813 #endif
4814 	nv_left(cap);
4815 }
4816 
4817 /*
4818  * CTRL-L: clear screen and redraw.
4819  */
4820     static void
4821 nv_clear(cap)
4822     cmdarg_T	*cap;
4823 {
4824     if (!checkclearop(cap->oap))
4825     {
4826 #if defined(__BEOS__) && !USE_THREAD_FOR_INPUT_WITH_TIMEOUT
4827 	/*
4828 	 * Right now, the BeBox doesn't seem to have an easy way to detect
4829 	 * window resizing, so we cheat and make the user detect it
4830 	 * manually with CTRL-L instead
4831 	 */
4832 	ui_get_shellsize();
4833 #endif
4834 #ifdef FEAT_SYN_HL
4835 	/* Clear all syntax states to force resyncing. */
4836 	syn_stack_free_all(curbuf);
4837 #endif
4838 	redraw_later(CLEAR);
4839     }
4840 }
4841 
4842 /*
4843  * CTRL-O: In Select mode: switch to Visual mode for one command.
4844  * Otherwise: Go to older pcmark.
4845  */
4846     static void
4847 nv_ctrlo(cap)
4848     cmdarg_T	*cap;
4849 {
4850 #ifdef FEAT_VISUAL
4851     if (VIsual_active && VIsual_select)
4852     {
4853 	VIsual_select = FALSE;
4854 	showmode();
4855 	restart_VIsual_select = 2;	/* restart Select mode later */
4856     }
4857     else
4858 #endif
4859     {
4860 	cap->count1 = -cap->count1;
4861 	nv_pcmark(cap);
4862     }
4863 }
4864 
4865 /*
4866  * CTRL-^ command, short for ":e #"
4867  */
4868     static void
4869 nv_hat(cap)
4870     cmdarg_T	*cap;
4871 {
4872     if (!checkclearopq(cap->oap))
4873 	(void)buflist_getfile((int)cap->count0, (linenr_T)0,
4874 						GETF_SETMARK|GETF_ALT, FALSE);
4875 }
4876 
4877 /*
4878  * "Z" commands.
4879  */
4880     static void
4881 nv_Zet(cap)
4882     cmdarg_T *cap;
4883 {
4884     if (!checkclearopq(cap->oap))
4885     {
4886 	switch (cap->nchar)
4887 	{
4888 			/* "ZZ": equivalent to ":x". */
4889 	    case 'Z':	do_cmdline_cmd((char_u *)"x");
4890 			break;
4891 
4892 			/* "ZQ": equivalent to ":q!" (Elvis compatible). */
4893 	    case 'Q':	do_cmdline_cmd((char_u *)"q!");
4894 			break;
4895 
4896 	    default:	clearopbeep(cap->oap);
4897 	}
4898     }
4899 }
4900 
4901 #if defined(FEAT_WINDOWS) || defined(PROTO)
4902 /*
4903  * Call nv_ident() as if "c1" was used, with "c2" as next character.
4904  */
4905     void
4906 do_nv_ident(c1, c2)
4907     int		c1;
4908     int		c2;
4909 {
4910     oparg_T	oa;
4911     cmdarg_T	ca;
4912 
4913     clear_oparg(&oa);
4914     vim_memset(&ca, 0, sizeof(ca));
4915     ca.oap = &oa;
4916     ca.cmdchar = c1;
4917     ca.nchar = c2;
4918     nv_ident(&ca);
4919 }
4920 #endif
4921 
4922 /*
4923  * Handle the commands that use the word under the cursor.
4924  * [g] CTRL-]	:ta to current identifier
4925  * [g] 'K'	run program for current identifier
4926  * [g] '*'	/ to current identifier or string
4927  * [g] '#'	? to current identifier or string
4928  *  g  ']'	:tselect for current identifier
4929  */
4930     static void
4931 nv_ident(cap)
4932     cmdarg_T	*cap;
4933 {
4934     char_u	*ptr = NULL;
4935     char_u	*buf;
4936     char_u	*p;
4937     char_u	*kp;		/* value of 'keywordprg' */
4938     int		kp_help;	/* 'keywordprg' is ":help" */
4939     int		n = 0;		/* init for GCC */
4940     int		cmdchar;
4941     int		g_cmd;		/* "g" command */
4942     char_u	*aux_ptr;
4943     int		isman;
4944     int		isman_s;
4945 
4946     if (cap->cmdchar == 'g')	/* "g*", "g#", "g]" and "gCTRL-]" */
4947     {
4948 	cmdchar = cap->nchar;
4949 	g_cmd = TRUE;
4950     }
4951     else
4952     {
4953 	cmdchar = cap->cmdchar;
4954 	g_cmd = FALSE;
4955     }
4956 
4957     if (cmdchar == POUND)	/* the pound sign, '#' for English keyboards */
4958 	cmdchar = '#';
4959 
4960     /*
4961      * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
4962      */
4963     if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K')
4964     {
4965 #ifdef FEAT_VISUAL
4966 	if (VIsual_active && get_visual_text(cap, &ptr, &n) == FAIL)
4967 	    return;
4968 #endif
4969 	if (checkclearopq(cap->oap))
4970 	    return;
4971     }
4972 
4973     if (ptr == NULL && (n = find_ident_under_cursor(&ptr,
4974 		    (cmdchar == '*' || cmdchar == '#')
4975 				 ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
4976     {
4977 	clearop(cap->oap);
4978 	return;
4979     }
4980 
4981     /* Allocate buffer to put the command in.  Inserting backslashes can
4982      * double the length of the word.  p_kp / curbuf->b_p_kp could be added
4983      * and some numbers. */
4984     kp = (*curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp);
4985     kp_help = (*kp == NUL || STRCMP(kp, ":he") == 0
4986 						 || STRCMP(kp, ":help") == 0);
4987     buf = alloc((unsigned)(n * 2 + 30 + STRLEN(kp)));
4988     if (buf == NULL)
4989 	return;
4990     buf[0] = NUL;
4991 
4992     switch (cmdchar)
4993     {
4994 	case '*':
4995 	case '#':
4996 	    /*
4997 	     * Put cursor at start of word, makes search skip the word
4998 	     * under the cursor.
4999 	     * Call setpcmark() first, so "*``" puts the cursor back where
5000 	     * it was.
5001 	     */
5002 	    setpcmark();
5003 	    curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline());
5004 
5005 	    if (!g_cmd && vim_iswordp(ptr))
5006 		STRCPY(buf, "\\<");
5007 	    no_smartcase = TRUE;	/* don't use 'smartcase' now */
5008 	    break;
5009 
5010 	case 'K':
5011 	    if (kp_help)
5012 		STRCPY(buf, "he! ");
5013 	    else
5014 	    {
5015 		/* When a count is given, turn it into a range.  Is this
5016 		 * really what we want? */
5017 		isman = (STRCMP(kp, "man") == 0);
5018 		isman_s = (STRCMP(kp, "man -s") == 0);
5019 		if (cap->count0 != 0 && !(isman || isman_s))
5020 		    sprintf((char *)buf, ".,.+%ld", cap->count0 - 1);
5021 
5022 		STRCAT(buf, "! ");
5023 		if (cap->count0 == 0 && isman_s)
5024 		    STRCAT(buf, "man");
5025 		else
5026 		    STRCAT(buf, kp);
5027 		STRCAT(buf, " ");
5028 		if (cap->count0 != 0 && (isman || isman_s))
5029 		{
5030 		    sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0);
5031 		    STRCAT(buf, " ");
5032 		}
5033 	    }
5034 	    break;
5035 
5036 	case ']':
5037 #ifdef FEAT_CSCOPE
5038 	    if (p_cst)
5039 		STRCPY(buf, "cstag ");
5040 	    else
5041 #endif
5042 		STRCPY(buf, "ts ");
5043 	    break;
5044 
5045 	default:
5046 	    if (curbuf->b_help)
5047 		STRCPY(buf, "he! ");
5048 	    else if (g_cmd)
5049 		STRCPY(buf, "tj ");
5050 	    else
5051 		STRCPY(buf, "ta ");
5052     }
5053 
5054     /*
5055      * Now grab the chars in the identifier
5056      */
5057     if (cmdchar == '*')
5058 	aux_ptr = (char_u *)(p_magic ? "/.*~[^$\\" : "/^$\\");
5059     else if (cmdchar == '#')
5060 	aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\\" : "/?^$\\");
5061     else if (cmdchar == 'K' && !kp_help)
5062 	aux_ptr = (char_u *)" \t\\\"|!";
5063     else
5064 	/* Don't escape spaces and Tabs in a tag with a backslash */
5065 	aux_ptr = (char_u *)"\\|\"";
5066 
5067     p = buf + STRLEN(buf);
5068     while (n-- > 0)
5069     {
5070 	/* put a backslash before \ and some others */
5071 	if (vim_strchr(aux_ptr, *ptr) != NULL)
5072 	    *p++ = '\\';
5073 #ifdef FEAT_MBYTE
5074 	/* When current byte is a part of multibyte character, copy all bytes
5075 	 * of that character. */
5076 	if (has_mbyte)
5077 	{
5078 	    int i;
5079 	    int len = (*mb_ptr2len_check)(ptr) - 1;
5080 
5081 	    for (i = 0; i < len && n >= 1; ++i, --n)
5082 		*p++ = *ptr++;
5083 	}
5084 #endif
5085 	*p++ = *ptr++;
5086     }
5087     *p = NUL;
5088 
5089     /*
5090      * Execute the command.
5091      */
5092     if (cmdchar == '*' || cmdchar == '#')
5093     {
5094 	if (!g_cmd && (
5095 #ifdef FEAT_MBYTE
5096 		has_mbyte ? vim_iswordp(mb_prevptr(ml_get_curline(), ptr)) :
5097 #endif
5098 		vim_iswordc(ptr[-1])))
5099 	    STRCAT(buf, "\\>");
5100 #ifdef FEAT_CMDHIST
5101 	/* put pattern in search history */
5102 	add_to_history(HIST_SEARCH, buf, TRUE, NUL);
5103 #endif
5104 	normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0);
5105     }
5106     else
5107 	do_cmdline_cmd(buf);
5108 
5109     vim_free(buf);
5110 }
5111 
5112 #ifdef FEAT_VISUAL
5113 /*
5114  * Get visually selected text, within one line only.
5115  * Returns FAIL if more than one line selected.
5116  */
5117     static int
5118 get_visual_text(cap, pp, lenp)
5119     cmdarg_T	*cap;
5120     char_u	**pp;	    /* return: start of selected text */
5121     int		*lenp;	    /* return: length of selected text */
5122 {
5123     if (VIsual_mode != 'V')
5124 	unadjust_for_sel();
5125     if (VIsual.lnum != curwin->w_cursor.lnum)
5126     {
5127 	clearopbeep(cap->oap);
5128 	return FAIL;
5129     }
5130     if (VIsual_mode == 'V')
5131     {
5132 	*pp = ml_get_curline();
5133 	*lenp = (int)STRLEN(*pp);
5134     }
5135     else
5136     {
5137 	if (lt(curwin->w_cursor, VIsual))
5138 	{
5139 	    *pp = ml_get_pos(&curwin->w_cursor);
5140 	    *lenp = VIsual.col - curwin->w_cursor.col + 1;
5141 	}
5142 	else
5143 	{
5144 	    *pp = ml_get_pos(&VIsual);
5145 	    *lenp = curwin->w_cursor.col - VIsual.col + 1;
5146 	}
5147 #ifdef FEAT_MBYTE
5148 	if (has_mbyte)
5149 	    /* Correct the length to include the whole last character. */
5150 	    *lenp += (*mb_ptr2len_check)(*pp + (*lenp - 1)) - 1;
5151 #endif
5152     }
5153     reset_VIsual_and_resel();
5154     return OK;
5155 }
5156 #endif
5157 
5158 /*
5159  * CTRL-T: backwards in tag stack
5160  */
5161     static void
5162 nv_tagpop(cap)
5163     cmdarg_T	*cap;
5164 {
5165     if (!checkclearopq(cap->oap))
5166 	do_tag((char_u *)"", DT_POP, (int)cap->count1, FALSE, TRUE);
5167 }
5168 
5169 /*
5170  * Handle scrolling command 'H', 'L' and 'M'.
5171  */
5172     static void
5173 nv_scroll(cap)
5174     cmdarg_T  *cap;
5175 {
5176     int		used = 0;
5177     long	n;
5178 #ifdef FEAT_FOLDING
5179     linenr_T	lnum;
5180 #endif
5181     int		half;
5182 
5183     cap->oap->motion_type = MLINE;
5184     setpcmark();
5185 
5186     if (cap->cmdchar == 'L')
5187     {
5188 	validate_botline();	    /* make sure curwin->w_botline is valid */
5189 	curwin->w_cursor.lnum = curwin->w_botline - 1;
5190 	if (cap->count1 - 1 >= curwin->w_cursor.lnum)
5191 	    curwin->w_cursor.lnum = 1;
5192 	else
5193 	{
5194 #ifdef FEAT_FOLDING
5195 	    if (hasAnyFolding(curwin))
5196 	    {
5197 		/* Count a fold for one screen line. */
5198 		for (n = cap->count1 - 1; n > 0
5199 			    && curwin->w_cursor.lnum > curwin->w_topline; --n)
5200 		{
5201 		    (void)hasFolding(curwin->w_cursor.lnum,
5202 						&curwin->w_cursor.lnum, NULL);
5203 		    --curwin->w_cursor.lnum;
5204 		}
5205 	    }
5206 	    else
5207 #endif
5208 		curwin->w_cursor.lnum -= cap->count1 - 1;
5209 	}
5210     }
5211     else
5212     {
5213 	if (cap->cmdchar == 'M')
5214 	{
5215 #ifdef FEAT_DIFF
5216 	    /* Don't count filler lines above the window. */
5217 	    used -= diff_check_fill(curwin, curwin->w_topline)
5218 							  - curwin->w_topfill;
5219 #endif
5220 	    validate_botline();	    /* make sure w_empty_rows is valid */
5221 	    half = (curwin->w_height - curwin->w_empty_rows + 1) / 2;
5222 	    for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
5223 	    {
5224 #ifdef FEAT_DIFF
5225 		/* Count half he number of filler lines to be "below this
5226 		 * line" and half to be "above the next line". */
5227 		if (n > 0 && used + diff_check_fill(curwin, curwin->w_topline
5228 							     + n) / 2 >= half)
5229 		{
5230 		    --n;
5231 		    break;
5232 		}
5233 #endif
5234 		used += plines(curwin->w_topline + n);
5235 		if (used >= half)
5236 		    break;
5237 #ifdef FEAT_FOLDING
5238 		if (hasFolding(curwin->w_topline + n, NULL, &lnum))
5239 		    n = lnum - curwin->w_topline;
5240 #endif
5241 	    }
5242 	    if (n > 0 && used > curwin->w_height)
5243 		--n;
5244 	}
5245 	else /* (cap->cmdchar == 'H') */
5246 	{
5247 	    n = cap->count1 - 1;
5248 #ifdef FEAT_FOLDING
5249 	    if (hasAnyFolding(curwin))
5250 	    {
5251 		/* Count a fold for one screen line. */
5252 		lnum = curwin->w_topline;
5253 		while (n-- > 0 && lnum < curwin->w_botline - 1)
5254 		{
5255 		    hasFolding(lnum, NULL, &lnum);
5256 		    ++lnum;
5257 		}
5258 		n = lnum - curwin->w_topline;
5259 	    }
5260 #endif
5261 	}
5262 	curwin->w_cursor.lnum = curwin->w_topline + n;
5263 	if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
5264 	    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5265     }
5266 
5267     cursor_correct();	/* correct for 'so' */
5268     beginline(BL_SOL | BL_FIX);
5269 }
5270 
5271 /*
5272  * Cursor right commands.
5273  */
5274     static void
5275 nv_right(cap)
5276     cmdarg_T	*cap;
5277 {
5278     long	n;
5279 #ifdef FEAT_VISUAL
5280     int		PAST_LINE;
5281 #else
5282 # define PAST_LINE 0
5283 #endif
5284 
5285     cap->oap->motion_type = MCHAR;
5286     cap->oap->inclusive = FALSE;
5287 #ifdef FEAT_VISUAL
5288     PAST_LINE = (VIsual_active && *p_sel != 'o');
5289 
5290 # ifdef FEAT_VIRTUALEDIT
5291     /*
5292      * In virtual mode, there's no such thing as "PAST_LINE", as lines are
5293      * (theoretically) infinitly long.
5294      */
5295     if (virtual_active())
5296 	PAST_LINE = 0;
5297 # endif
5298 #endif
5299 
5300     for (n = cap->count1; n > 0; --n)
5301     {
5302 	if ((!PAST_LINE && oneright() == FAIL)
5303 		|| (PAST_LINE && *ml_get_cursor() == NUL))
5304 	{
5305 	    /*
5306 	     *	  <Space> wraps to next line if 'whichwrap' bit 1 set.
5307 	     *	      'l' wraps to next line if 'whichwrap' bit 2 set.
5308 	     * CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set
5309 	     */
5310 	    if (       ((cap->cmdchar == ' '
5311 			    && vim_strchr(p_ww, 's') != NULL)
5312 			|| (cap->cmdchar == 'l'
5313 			    && vim_strchr(p_ww, 'l') != NULL)
5314 			|| (cap->cmdchar == K_RIGHT
5315 			    && vim_strchr(p_ww, '>') != NULL))
5316 		    && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
5317 	    {
5318 		/* When deleting we also count the NL as a character.
5319 		 * Set cap->oap->inclusive when last char in the line is
5320 		 * included, move to next line after that */
5321 		if (	   (cap->oap->op_type == OP_DELETE
5322 			    || cap->oap->op_type == OP_CHANGE)
5323 			&& !cap->oap->inclusive
5324 			&& !lineempty(curwin->w_cursor.lnum))
5325 		    cap->oap->inclusive = TRUE;
5326 		else
5327 		{
5328 		    ++curwin->w_cursor.lnum;
5329 		    curwin->w_cursor.col = 0;
5330 #ifdef FEAT_VIRTUALEDIT
5331 		    curwin->w_cursor.coladd = 0;
5332 #endif
5333 		    curwin->w_set_curswant = TRUE;
5334 		    cap->oap->inclusive = FALSE;
5335 		}
5336 		continue;
5337 	    }
5338 	    if (cap->oap->op_type == OP_NOP)
5339 	    {
5340 		/* Only beep and flush if not moved at all */
5341 		if (n == cap->count1)
5342 		    beep_flush();
5343 	    }
5344 	    else
5345 	    {
5346 		if (!lineempty(curwin->w_cursor.lnum))
5347 		    cap->oap->inclusive = TRUE;
5348 	    }
5349 	    break;
5350 	}
5351 #ifdef FEAT_VISUAL
5352 	else if (PAST_LINE)
5353 	{
5354 	    curwin->w_set_curswant = TRUE;
5355 # ifdef FEAT_VIRTUALEDIT
5356 	    if (virtual_active())
5357 		oneright();
5358 	    else
5359 # endif
5360 	    {
5361 # ifdef FEAT_MBYTE
5362 		if (has_mbyte)
5363 		    curwin->w_cursor.col +=
5364 					 (*mb_ptr2len_check)(ml_get_cursor());
5365 		else
5366 # endif
5367 		    ++curwin->w_cursor.col;
5368 	    }
5369 	}
5370 #endif
5371     }
5372 #ifdef FEAT_FOLDING
5373     if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
5374 					       && cap->oap->op_type == OP_NOP)
5375 	foldOpenCursor();
5376 #endif
5377 }
5378 
5379 /*
5380  * Cursor left commands.
5381  *
5382  * Returns TRUE when operator end should not be adjusted.
5383  */
5384     static void
5385 nv_left(cap)
5386     cmdarg_T	*cap;
5387 {
5388     long	n;
5389 
5390     cap->oap->motion_type = MCHAR;
5391     cap->oap->inclusive = FALSE;
5392     for (n = cap->count1; n > 0; --n)
5393     {
5394 	if (oneleft() == FAIL)
5395 	{
5396 	    /* <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'.
5397 	     *		 'h' wraps to previous line if 'whichwrap' has 'h'.
5398 	     *	   CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
5399 	     */
5400 	    if (       (((cap->cmdchar == K_BS
5401 				|| cap->cmdchar == Ctrl_H)
5402 			    && vim_strchr(p_ww, 'b') != NULL)
5403 			|| (cap->cmdchar == 'h'
5404 			    && vim_strchr(p_ww, 'h') != NULL)
5405 			|| (cap->cmdchar == K_LEFT
5406 			    && vim_strchr(p_ww, '<') != NULL))
5407 		    && curwin->w_cursor.lnum > 1)
5408 	    {
5409 		--(curwin->w_cursor.lnum);
5410 		coladvance((colnr_T)MAXCOL);
5411 		curwin->w_set_curswant = TRUE;
5412 
5413 		/* When the NL before the first char has to be deleted we
5414 		 * put the cursor on the NUL after the previous line.
5415 		 * This is a very special case, be careful!
5416 		 * don't adjust op_end now, otherwise it won't work */
5417 		if (	   (cap->oap->op_type == OP_DELETE
5418 			    || cap->oap->op_type == OP_CHANGE)
5419 			&& !lineempty(curwin->w_cursor.lnum))
5420 		{
5421 		    ++curwin->w_cursor.col;
5422 		    cap->retval |= CA_NO_ADJ_OP_END;
5423 		}
5424 		continue;
5425 	    }
5426 	    /* Only beep and flush if not moved at all */
5427 	    else if (cap->oap->op_type == OP_NOP && n == cap->count1)
5428 		beep_flush();
5429 	    break;
5430 	}
5431     }
5432 #ifdef FEAT_FOLDING
5433     if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
5434 					       && cap->oap->op_type == OP_NOP)
5435 	foldOpenCursor();
5436 #endif
5437 }
5438 
5439 /*
5440  * Cursor up commands.
5441  * cap->arg is TRUE for "-": Move cursor to first non-blank.
5442  */
5443     static void
5444 nv_up(cap)
5445     cmdarg_T	*cap;
5446 {
5447     cap->oap->motion_type = MLINE;
5448     if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == FAIL)
5449 	clearopbeep(cap->oap);
5450     else if (cap->arg)
5451 	beginline(BL_WHITE | BL_FIX);
5452 }
5453 
5454 /*
5455  * Cursor down commands.
5456  * cap->arg is TRUE for CR and "+": Move cursor to first non-blank.
5457  */
5458     static void
5459 nv_down(cap)
5460     cmdarg_T	*cap;
5461 {
5462 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
5463     /* In a quickfix window a <CR> jumps to the error under the cursor. */
5464     if (bt_quickfix(curbuf) && cap->cmdchar == '\r')
5465 	do_cmdline_cmd((char_u *)".cc");
5466     else
5467 #endif
5468     {
5469 #ifdef FEAT_CMDWIN
5470 	/* In the cmdline window a <CR> executes the command. */
5471 	if (cmdwin_type != 0 && cap->cmdchar == '\r')
5472 	    cmdwin_result = CAR;
5473 	else
5474 #endif
5475 	{
5476 	    cap->oap->motion_type = MLINE;
5477 	    if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == FAIL)
5478 		clearopbeep(cap->oap);
5479 	    else if (cap->arg)
5480 		beginline(BL_WHITE | BL_FIX);
5481 	}
5482     }
5483 }
5484 
5485 #ifdef FEAT_SEARCHPATH
5486 /*
5487  * Grab the file name under the cursor and edit it.
5488  */
5489     static void
5490 nv_gotofile(cap)
5491     cmdarg_T	*cap;
5492 {
5493     char_u	*ptr;
5494 
5495 #ifdef FEAT_CMDWIN
5496     if (cmdwin_type != 0)
5497     {
5498 	clearopbeep(cap->oap);
5499 	return;
5500     }
5501 #endif
5502 
5503 # ifdef FEAT_VISUAL
5504     /*
5505      * In Visual mode, use the selected text as a file name.
5506      * Don't allow selection across multiple lines.
5507      */
5508     if (VIsual_active)
5509     {
5510 	int	len;
5511 
5512 	if (get_visual_text(cap, &ptr, &len) == FAIL)
5513 	    return;
5514 	ptr = find_file_name_in_path(ptr, len,
5515 	       FNAME_MESS|FNAME_EXP|FNAME_REL, cap->count1, curbuf->b_ffname);
5516     }
5517     else
5518 # endif
5519 	ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP|FNAME_REL,
5520 								 cap->count1);
5521 
5522     if (ptr != NULL)
5523     {
5524 	/* do autowrite if necessary */
5525 	if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf))
5526 	    autowrite(curbuf, FALSE);
5527 	setpcmark();
5528 	(void)do_ecmd(0, ptr, NULL, NULL, ECMD_LAST,
5529 					       P_HID(curbuf) ? ECMD_HIDE : 0);
5530 	vim_free(ptr);
5531     }
5532     else
5533 	clearop(cap->oap);
5534 }
5535 #endif
5536 
5537 /*
5538  * <End> command: to end of current line or last line.
5539  */
5540     static void
5541 nv_end(cap)
5542     cmdarg_T	*cap;
5543 {
5544     if (cap->arg)	/* CTRL-END = goto last line */
5545     {
5546 	nv_goto(cap);
5547 	cap->count1 = 1;		/* to end of current line */
5548     }
5549     nv_dollar(cap);
5550 }
5551 
5552 /*
5553  * Handle the "$" command.
5554  */
5555     static void
5556 nv_dollar(cap)
5557     cmdarg_T	*cap;
5558 {
5559     cap->oap->motion_type = MCHAR;
5560     cap->oap->inclusive = TRUE;
5561 #ifdef FEAT_VIRTUALEDIT
5562     /* In virtual mode when off the edge of a line and an operator
5563      * is pending (whew!) keep the cursor where it is.
5564      * Otherwise, send it to the end of the line. */
5565     if (!virtual_active() || gchar_cursor() != NUL
5566 					       || cap->oap->op_type == OP_NOP)
5567 #endif
5568 	curwin->w_curswant = MAXCOL;	/* so we stay at the end */
5569     if (cursor_down((long)(cap->count1 - 1),
5570 					 cap->oap->op_type == OP_NOP) == FAIL)
5571 	clearopbeep(cap->oap);
5572 #ifdef FEAT_FOLDING
5573     else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
5574 	foldOpenCursor();
5575 #endif
5576 }
5577 
5578 /*
5579  * Implementation of '?' and '/' commands.
5580  * If cap->arg is TRUE don't set PC mark.
5581  */
5582     static void
5583 nv_search(cap)
5584     cmdarg_T	    *cap;
5585 {
5586     oparg_T	*oap = cap->oap;
5587 
5588     if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13)
5589     {
5590 	/* Translate "g??" to "g?g?" */
5591 	cap->cmdchar = 'g';
5592 	cap->nchar = '?';
5593 	nv_operator(cap);
5594 	return;
5595     }
5596 
5597     cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
5598 
5599     if (cap->searchbuf == NULL)
5600     {
5601 	clearop(oap);
5602 	return;
5603     }
5604 
5605     normal_search(cap, cap->cmdchar, cap->searchbuf,
5606 						(cap->arg ? 0 : SEARCH_MARK));
5607 }
5608 
5609 /*
5610  * Handle "N" and "n" commands.
5611  * cap->arg is SEARCH_REV for "N", 0 for "n".
5612  */
5613     static void
5614 nv_next(cap)
5615     cmdarg_T	*cap;
5616 {
5617     normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg);
5618 }
5619 
5620 /*
5621  * Search for "pat" in direction "dir" ('/' or '?', 0 for repeat).
5622  * Uses only cap->count1 and cap->oap from "cap".
5623  */
5624     static void
5625 normal_search(cap, dir, pat, opt)
5626     cmdarg_T	*cap;
5627     int		dir;
5628     char_u	*pat;
5629     int		opt;		/* extra flags for do_search() */
5630 {
5631     int		i;
5632 
5633     cap->oap->motion_type = MCHAR;
5634     cap->oap->inclusive = FALSE;
5635     cap->oap->use_reg_one = TRUE;
5636     curwin->w_set_curswant = TRUE;
5637 
5638     i = do_search(cap->oap, dir, pat, cap->count1,
5639 				 opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
5640     if (i == 0)
5641 	clearop(cap->oap);
5642     else
5643     {
5644 	if (i == 2)
5645 	    cap->oap->motion_type = MLINE;
5646 #ifdef FEAT_VIRTUALEDIT
5647 	curwin->w_cursor.coladd = 0;
5648 #endif
5649 #ifdef FEAT_FOLDING
5650 	if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
5651 	    foldOpenCursor();
5652 #endif
5653     }
5654 
5655     /* "/$" will put the cursor after the end of the line, may need to
5656      * correct that here */
5657     check_cursor();
5658 }
5659 
5660 /*
5661  * Character search commands.
5662  * cap->arg is BACKWARD for 'F' and 'T', FORWARD for 'f' and 't', TRUE for
5663  * ',' and FALSE for ';'.
5664  * cap->nchar is NUL for ',' and ';' (repeat the search)
5665  */
5666     static void
5667 nv_csearch(cap)
5668     cmdarg_T	*cap;
5669 {
5670     int		t_cmd;
5671 
5672     if (cap->cmdchar == 't' || cap->cmdchar == 'T')
5673 	t_cmd = TRUE;
5674     else
5675 	t_cmd = FALSE;
5676 
5677     cap->oap->motion_type = MCHAR;
5678     if (cap->arg == BACKWARD)
5679 	cap->oap->inclusive = FALSE;
5680     else
5681 	cap->oap->inclusive = TRUE;
5682     if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == FAIL)
5683 	clearopbeep(cap->oap);
5684     else
5685     {
5686 	curwin->w_set_curswant = TRUE;
5687 #ifdef FEAT_VIRTUALEDIT
5688 	/* Include a Tab for "tx" and for "dfx". */
5689 	if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD
5690 		&& (t_cmd || cap->oap->op_type != OP_NOP))
5691 	{
5692 	    colnr_T	scol, ecol;
5693 
5694 	    getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
5695 	    curwin->w_cursor.coladd = ecol - scol;
5696 	}
5697 	else
5698 	    curwin->w_cursor.coladd = 0;
5699 #endif
5700 #ifdef FEAT_VISUAL
5701 	adjust_for_sel(cap);
5702 #endif
5703 #ifdef FEAT_FOLDING
5704 	if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
5705 	    foldOpenCursor();
5706 #endif
5707     }
5708 }
5709 
5710 /*
5711  * "[" and "]" commands.
5712  * cap->arg is BACKWARD for "[" and FORWARD for "]".
5713  */
5714     static void
5715 nv_brackets(cap)
5716     cmdarg_T	*cap;
5717 {
5718     pos_T	new_pos;
5719     pos_T	prev_pos;
5720     pos_T	*pos = NULL;	    /* init for GCC */
5721     pos_T	old_pos;	    /* cursor position before command */
5722     int		flag;
5723     long	n;
5724     int		findc;
5725     int		c;
5726 
5727     cap->oap->motion_type = MCHAR;
5728     cap->oap->inclusive = FALSE;
5729     old_pos = curwin->w_cursor;
5730 #ifdef FEAT_VIRTUALEDIT
5731     curwin->w_cursor.coladd = 0;	    /* TODO: don't do this for an error. */
5732 #endif
5733 
5734 #ifdef FEAT_SEARCHPATH
5735     /*
5736      * "[f" or "]f" : Edit file under the cursor (same as "gf")
5737      */
5738     if (cap->nchar == 'f')
5739 	nv_gotofile(cap);
5740     else
5741 #endif
5742 
5743 #ifdef FEAT_FIND_ID
5744     /*
5745      * Find the occurence(s) of the identifier or define under cursor
5746      * in current and included files or jump to the first occurence.
5747      *
5748      *			search	     list	    jump
5749      *		      fwd   bwd    fwd	 bwd	 fwd	bwd
5750      * identifier     "]i"  "[i"   "]I"  "[I"	"]^I"  "[^I"
5751      * define	      "]d"  "[d"   "]D"  "[D"	"]^D"  "[^D"
5752      */
5753     if (vim_strchr((char_u *)
5754 #ifdef EBCDIC
5755 		"iI\005dD\067",
5756 #else
5757 		"iI\011dD\004",
5758 #endif
5759 		cap->nchar) != NULL)
5760     {
5761 	char_u	*ptr;
5762 	int	len;
5763 
5764 	if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
5765 	    clearop(cap->oap);
5766 	else
5767 	{
5768 	    find_pattern_in_path(ptr, 0, len, TRUE,
5769 		cap->count0 == 0 ? !isupper(cap->nchar) : FALSE,
5770 		((cap->nchar & 0xf) == ('d' & 0xf)) ?  FIND_DEFINE : FIND_ANY,
5771 		cap->count1,
5772 		isupper(cap->nchar) ? ACTION_SHOW_ALL :
5773 			    islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO,
5774 		cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : (linenr_T)1,
5775 		(linenr_T)MAXLNUM);
5776 	    curwin->w_set_curswant = TRUE;
5777 	}
5778     }
5779     else
5780 #endif
5781 
5782     /*
5783      * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
5784      * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
5785      * "[/", "[*", "]/", "]*": go to Nth comment start/end.
5786      * "[m" or "]m" search for prev/next start of (Java) method.
5787      * "[M" or "]M" search for prev/next end of (Java) method.
5788      */
5789     if (  (cap->cmdchar == '['
5790 		&& vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL)
5791 	    || (cap->cmdchar == ']'
5792 		&& vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL))
5793     {
5794 	if (cap->nchar == '*')
5795 	    cap->nchar = '/';
5796 	new_pos.lnum = 0;
5797 	prev_pos.lnum = 0;
5798 	if (cap->nchar == 'm' || cap->nchar == 'M')
5799 	{
5800 	    if (cap->cmdchar == '[')
5801 		findc = '{';
5802 	    else
5803 		findc = '}';
5804 	    n = 9999;
5805 	}
5806 	else
5807 	{
5808 	    findc = cap->nchar;
5809 	    n = cap->count1;
5810 	}
5811 	for ( ; n > 0; --n)
5812 	{
5813 	    if ((pos = findmatchlimit(cap->oap, findc,
5814 		(cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
5815 	    {
5816 		if (new_pos.lnum == 0)	/* nothing found */
5817 		{
5818 		    if (cap->nchar != 'm' && cap->nchar != 'M')
5819 			clearopbeep(cap->oap);
5820 		}
5821 		else
5822 		    pos = &new_pos;	/* use last one found */
5823 		break;
5824 	    }
5825 	    prev_pos = new_pos;
5826 	    curwin->w_cursor = *pos;
5827 	    new_pos = *pos;
5828 	}
5829 	curwin->w_cursor = old_pos;
5830 
5831 	/*
5832 	 * Handle "[m", "]m", "[M" and "[M".  The findmatchlimit() only
5833 	 * brought us to the match for "[m" and "]M" when inside a method.
5834 	 * Try finding the '{' or '}' we want to be at.
5835 	 * Also repeat for the given count.
5836 	 */
5837 	if (cap->nchar == 'm' || cap->nchar == 'M')
5838 	{
5839 	    /* norm is TRUE for "]M" and "[m" */
5840 	    int	    norm = ((findc == '{') == (cap->nchar == 'm'));
5841 
5842 	    n = cap->count1;
5843 	    /* found a match: we were inside a method */
5844 	    if (prev_pos.lnum != 0)
5845 	    {
5846 		pos = &prev_pos;
5847 		curwin->w_cursor = prev_pos;
5848 		if (norm)
5849 		    --n;
5850 	    }
5851 	    else
5852 		pos = NULL;
5853 	    while (n > 0)
5854 	    {
5855 		for (;;)
5856 		{
5857 		    if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0)
5858 		    {
5859 			/* if not found anything, that's an error */
5860 			if (pos == NULL)
5861 			    clearopbeep(cap->oap);
5862 			n = 0;
5863 			break;
5864 		    }
5865 		    c = gchar_cursor();
5866 		    if (c == '{' || c == '}')
5867 		    {
5868 			/* Must have found end/start of class: use it.
5869 			 * Or found the place to be at. */
5870 			if ((c == findc && norm) || (n == 1 && !norm))
5871 			{
5872 			    new_pos = curwin->w_cursor;
5873 			    pos = &new_pos;
5874 			    n = 0;
5875 			}
5876 			/* if no match found at all, we started outside of the
5877 			 * class and we're inside now.  Just go on. */
5878 			else if (new_pos.lnum == 0)
5879 			{
5880 			    new_pos = curwin->w_cursor;
5881 			    pos = &new_pos;
5882 			}
5883 			/* found start/end of other method: go to match */
5884 			else if ((pos = findmatchlimit(cap->oap, findc,
5885 			    (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD,
5886 								  0)) == NULL)
5887 			    n = 0;
5888 			else
5889 			    curwin->w_cursor = *pos;
5890 			break;
5891 		    }
5892 		}
5893 		--n;
5894 	    }
5895 	    curwin->w_cursor = old_pos;
5896 	    if (pos == NULL && new_pos.lnum != 0)
5897 		clearopbeep(cap->oap);
5898 	}
5899 	if (pos != NULL)
5900 	{
5901 	    setpcmark();
5902 	    curwin->w_cursor = *pos;
5903 	    curwin->w_set_curswant = TRUE;
5904 #ifdef FEAT_FOLDING
5905 	    if ((fdo_flags & FDO_BLOCK) && KeyTyped
5906 					       && cap->oap->op_type == OP_NOP)
5907 		foldOpenCursor();
5908 #endif
5909 	}
5910     }
5911 
5912     /*
5913      * "[[", "[]", "]]" and "][": move to start or end of function
5914      */
5915     else if (cap->nchar == '[' || cap->nchar == ']')
5916     {
5917 	if (cap->nchar == cap->cmdchar)		    /* "]]" or "[[" */
5918 	    flag = '{';
5919 	else
5920 	    flag = '}';		    /* "][" or "[]" */
5921 
5922 	curwin->w_set_curswant = TRUE;
5923 	/*
5924 	 * Imitate strange Vi behaviour: When using "]]" with an operator
5925 	 * we also stop at '}'.
5926 	 */
5927 	if (!findpar(cap->oap, cap->arg, cap->count1, flag,
5928 	      (cap->oap->op_type != OP_NOP
5929 				      && cap->arg == FORWARD && flag == '{')))
5930 	    clearopbeep(cap->oap);
5931 	else
5932 	{
5933 	    if (cap->oap->op_type == OP_NOP)
5934 		beginline(BL_WHITE | BL_FIX);
5935 #ifdef FEAT_FOLDING
5936 	    if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
5937 		foldOpenCursor();
5938 #endif
5939 	}
5940     }
5941 
5942     /*
5943      * "[p", "[P", "]P" and "]p": put with indent adjustment
5944      */
5945     else if (cap->nchar == 'p' || cap->nchar == 'P')
5946     {
5947 	if (!checkclearopq(cap->oap))
5948 	{
5949 	    prep_redo_cmd(cap);
5950 	    do_put(cap->oap->regname,
5951 	      (cap->cmdchar == ']' && cap->nchar == 'p') ? FORWARD : BACKWARD,
5952 						  cap->count1, PUT_FIXINDENT);
5953 	}
5954     }
5955 
5956     /*
5957      * "['", "[`", "]'" and "]`": jump to next mark
5958      */
5959     else if (cap->nchar == '\'' || cap->nchar == '`')
5960     {
5961 	pos = &curwin->w_cursor;
5962 	for (n = cap->count1; n > 0; --n)
5963 	{
5964 	    prev_pos = *pos;
5965 	    pos = getnextmark(pos, cap->cmdchar == '[' ? BACKWARD : FORWARD,
5966 							  cap->nchar == '\'');
5967 	    if (pos == NULL)
5968 		break;
5969 	}
5970 	if (pos == NULL)
5971 	    pos = &prev_pos;
5972 	nv_cursormark(cap, cap->nchar == '\'', pos);
5973     }
5974 
5975 #ifdef FEAT_MOUSE
5976     /*
5977      * [ or ] followed by a middle mouse click: put selected text with
5978      * indent adjustment.  Any other button just does as usual.
5979      */
5980     else if (cap->nchar >= K_LEFTMOUSE && cap->nchar <= K_RIGHTRELEASE)
5981     {
5982 	(void)do_mouse(cap->oap, cap->nchar,
5983 		       (cap->cmdchar == ']') ? FORWARD : BACKWARD,
5984 		       cap->count1, PUT_FIXINDENT);
5985     }
5986 #endif /* FEAT_MOUSE */
5987 
5988 #ifdef FEAT_FOLDING
5989     /*
5990      * "[z" and "]z": move to start or end of open fold.
5991      */
5992     else if (cap->nchar == 'z')
5993     {
5994 	if (foldMoveTo(FALSE, cap->cmdchar == ']' ? FORWARD : BACKWARD,
5995 							 cap->count1) == FAIL)
5996 	    clearopbeep(cap->oap);
5997     }
5998 #endif
5999 
6000 #ifdef FEAT_DIFF
6001     /*
6002      * "[c" and "]c": move to next or previous diff-change.
6003      */
6004     else if (cap->nchar == 'c')
6005     {
6006 	if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD,
6007 							 cap->count1) == FAIL)
6008 	    clearopbeep(cap->oap);
6009     }
6010 #endif
6011 
6012     /* Not a valid cap->nchar. */
6013     else
6014 	clearopbeep(cap->oap);
6015 }
6016 
6017 /*
6018  * Handle Normal mode "%" command.
6019  */
6020     static void
6021 nv_percent(cap)
6022     cmdarg_T	*cap;
6023 {
6024     pos_T	*pos;
6025 #ifdef FEAT_FOLDING
6026     linenr_T	lnum = curwin->w_cursor.lnum;
6027 #endif
6028 
6029     cap->oap->inclusive = TRUE;
6030     if (cap->count0)	    /* {cnt}% : goto {cnt} percentage in file */
6031     {
6032 	if (cap->count0 > 100)
6033 	    clearopbeep(cap->oap);
6034 	else
6035 	{
6036 	    cap->oap->motion_type = MLINE;
6037 	    setpcmark();
6038 	    /* Round up, so CTRL-G will give same value.  Watch out for a
6039 	     * large line count, the line number must not go negative! */
6040 	    if (curbuf->b_ml.ml_line_count > 1000000)
6041 		curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count + 99L)
6042 							 / 100L * cap->count0;
6043 	    else
6044 		curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
6045 						    cap->count0 + 99L) / 100L;
6046 	    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6047 		curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6048 	    beginline(BL_SOL | BL_FIX);
6049 	}
6050     }
6051     else		    /* "%" : go to matching paren */
6052     {
6053 	cap->oap->motion_type = MCHAR;
6054 	cap->oap->use_reg_one = TRUE;
6055 	if ((pos = findmatch(cap->oap, NUL)) == NULL)
6056 	    clearopbeep(cap->oap);
6057 	else
6058 	{
6059 	    setpcmark();
6060 	    curwin->w_cursor = *pos;
6061 	    curwin->w_set_curswant = TRUE;
6062 #ifdef FEAT_VIRTUALEDIT
6063 	    curwin->w_cursor.coladd = 0;
6064 #endif
6065 #ifdef FEAT_VISUAL
6066 	    adjust_for_sel(cap);
6067 #endif
6068 	}
6069     }
6070 #ifdef FEAT_FOLDING
6071     if (cap->oap->op_type == OP_NOP
6072 	    && lnum != curwin->w_cursor.lnum
6073 	    && (fdo_flags & FDO_PERCENT)
6074 	    && KeyTyped)
6075 	foldOpenCursor();
6076 #endif
6077 }
6078 
6079 /*
6080  * Handle "(" and ")" commands.
6081  * cap->arg is BACKWARD for "(" and FORWARD for ")".
6082  */
6083     static void
6084 nv_brace(cap)
6085     cmdarg_T	*cap;
6086 {
6087     cap->oap->motion_type = MCHAR;
6088     cap->oap->use_reg_one = TRUE;
6089     if (cap->cmdchar == ')')
6090 	cap->oap->inclusive = FALSE;
6091     else
6092 	cap->oap->inclusive = TRUE;
6093     curwin->w_set_curswant = TRUE;
6094 
6095     if (findsent(cap->arg, cap->count1) == FAIL)
6096 	clearopbeep(cap->oap);
6097     else
6098     {
6099 #ifdef FEAT_VIRTUALEDIT
6100 	curwin->w_cursor.coladd = 0;
6101 #endif
6102 #ifdef FEAT_FOLDING
6103 	if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
6104 	    foldOpenCursor();
6105 #endif
6106     }
6107 }
6108 
6109 /*
6110  * "m" command: Mark a position.
6111  */
6112     static void
6113 nv_mark(cap)
6114     cmdarg_T	*cap;
6115 {
6116     if (!checkclearop(cap->oap))
6117     {
6118 	if (setmark(cap->nchar) == FAIL)
6119 	    clearopbeep(cap->oap);
6120     }
6121 }
6122 
6123 /*
6124  * "{" and "}" commands.
6125  * cmd->arg is BACKWARD for "{" and FORWARD for "}".
6126  */
6127     static void
6128 nv_findpar(cap)
6129     cmdarg_T	*cap;
6130 {
6131     cap->oap->motion_type = MCHAR;
6132     cap->oap->inclusive = FALSE;
6133     cap->oap->use_reg_one = TRUE;
6134     curwin->w_set_curswant = TRUE;
6135     if (!findpar(cap->oap, cap->arg, cap->count1, NUL, FALSE))
6136 	clearopbeep(cap->oap);
6137     else
6138     {
6139 #ifdef FEAT_VIRTUALEDIT
6140 	curwin->w_cursor.coladd = 0;
6141 #endif
6142 #ifdef FEAT_FOLDING
6143 	if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
6144 	    foldOpenCursor();
6145 #endif
6146     }
6147 }
6148 
6149 /*
6150  * "u" command: Undo or make lower case.
6151  */
6152     static void
6153 nv_undo(cap)
6154     cmdarg_T	*cap;
6155 {
6156     if (cap->oap->op_type == OP_LOWER
6157 #ifdef FEAT_VISUAL
6158 	    || VIsual_active
6159 #endif
6160 	    )
6161     {
6162 	/* translate "<Visual>u" to "<Visual>gu" and "guu" to "gugu" */
6163 	cap->cmdchar = 'g';
6164 	cap->nchar = 'u';
6165 	nv_operator(cap);
6166     }
6167     else
6168 	nv_kundo(cap);
6169 }
6170 
6171 /*
6172  * <Undo> command.
6173  */
6174     static void
6175 nv_kundo(cap)
6176     cmdarg_T	*cap;
6177 {
6178     if (!checkclearopq(cap->oap))
6179     {
6180 	u_undo((int)cap->count1);
6181 	curwin->w_set_curswant = TRUE;
6182     }
6183 }
6184 
6185 /*
6186  * Handle the "r" command.
6187  */
6188     static void
6189 nv_replace(cap)
6190     cmdarg_T	*cap;
6191 {
6192     char_u	*ptr;
6193     int		had_ctrl_v;
6194     long	n;
6195 
6196     if (checkclearop(cap->oap))
6197 	return;
6198 
6199     /* get another character */
6200     if (cap->nchar == Ctrl_V)
6201     {
6202 	had_ctrl_v = Ctrl_V;
6203 	cap->nchar = get_literal();
6204 	/* Don't redo a multibyte character with CTRL-V. */
6205 	if (cap->nchar > DEL)
6206 	    had_ctrl_v = NUL;
6207     }
6208     else
6209 	had_ctrl_v = NUL;
6210 
6211 #ifdef FEAT_VISUAL
6212     /* Visual mode "r" */
6213     if (VIsual_active)
6214     {
6215 	nv_operator(cap);
6216 	return;
6217     }
6218 #endif
6219 
6220 #ifdef FEAT_VIRTUALEDIT
6221     /* Break tabs, etc. */
6222     if (virtual_active())
6223     {
6224 	if (u_save_cursor() == FAIL)
6225 	    return;
6226 	if (gchar_cursor() == NUL)
6227 	{
6228 	    /* Add extra space and put the cursor on the first one. */
6229 	    coladvance_force((colnr_T)(getviscol() + cap->count1));
6230 	    curwin->w_cursor.col -= cap->count1;
6231 	}
6232 	else if (gchar_cursor() == TAB)
6233 	    coladvance_force(getviscol());
6234     }
6235 #endif
6236 
6237     /*
6238      * Check for a special key or not enough characters to replace.
6239      */
6240     ptr = ml_get_cursor();
6241     if (IS_SPECIAL(cap->nchar) || STRLEN(ptr) < (unsigned)cap->count1
6242 #ifdef FEAT_MBYTE
6243 	    || (has_mbyte && mb_charlen(ptr) < cap->count1)
6244 #endif
6245 	    )
6246     {
6247 	clearopbeep(cap->oap);
6248 	return;
6249     }
6250 
6251     /*
6252      * Replacing with a TAB is done by edit() when it is complicated because
6253      * 'expandtab' or 'smarttab' is set.  CTRL-V TAB inserts a literal TAB.
6254      * Other characters are done below to avoid problems with things like
6255      * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
6256      */
6257     if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || p_sta))
6258     {
6259 	stuffnumReadbuff(cap->count1);
6260 	stuffcharReadbuff('R');
6261 	stuffcharReadbuff('\t');
6262 	stuffcharReadbuff(ESC);
6263 	return;
6264     }
6265 
6266     /* save line for undo */
6267     if (u_save_cursor() == FAIL)
6268 	return;
6269 
6270     if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n'))
6271     {
6272 	/*
6273 	 * Replace character(s) by a single newline.
6274 	 * Strange vi behaviour: Only one newline is inserted.
6275 	 * Delete the characters here.
6276 	 * Insert the newline with an insert command, takes care of
6277 	 * autoindent.	The insert command depends on being on the last
6278 	 * character of a line or not.
6279 	 */
6280 #ifdef FEAT_MBYTE
6281 	(void)del_chars(cap->count1, FALSE);	/* delete the characters */
6282 #else
6283 	(void)del_bytes(cap->count1, FALSE);	/* delete the characters */
6284 #endif
6285 	stuffcharReadbuff('\r');
6286 	stuffcharReadbuff(ESC);
6287 
6288 	/* Give 'r' to edit(), to get the redo command right. */
6289 	invoke_edit(cap, TRUE, 'r', FALSE);
6290     }
6291     else
6292     {
6293 	prep_redo(cap->oap->regname, cap->count1,
6294 				       NUL, 'r', NUL, had_ctrl_v, cap->nchar);
6295 
6296 	curbuf->b_op_start = curwin->w_cursor;
6297 #ifdef FEAT_MBYTE
6298 	if (has_mbyte)
6299 	{
6300 	    int		old_State = State;
6301 
6302 	    if (cap->ncharC1 != 0)
6303 		AppendCharToRedobuff(cap->ncharC1);
6304 	    if (cap->ncharC2 != 0)
6305 		AppendCharToRedobuff(cap->ncharC2);
6306 
6307 	    /* This is slow, but it handles replacing a single-byte with a
6308 	     * multi-byte and the other way around.  Also handles adding
6309 	     * composing characters for utf-8. */
6310 	    for (n = cap->count1; n > 0; --n)
6311 	    {
6312 		State = REPLACE;
6313 		ins_char(cap->nchar);
6314 		State = old_State;
6315 		if (cap->ncharC1 != 0)
6316 		    ins_char(cap->ncharC1);
6317 		if (cap->ncharC2 != 0)
6318 		    ins_char(cap->ncharC2);
6319 	    }
6320 	}
6321 	else
6322 #endif
6323 	{
6324 	    /*
6325 	     * Replace the characters within one line.
6326 	     */
6327 	    for (n = cap->count1; n > 0; --n)
6328 	    {
6329 		/*
6330 		 * Get ptr again, because u_save and/or showmatch() will have
6331 		 * released the line.  At the same time we let know that the
6332 		 * line will be changed.
6333 		 */
6334 		ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
6335 		ptr[curwin->w_cursor.col] = cap->nchar;
6336 		if (p_sm && msg_silent == 0)
6337 		    showmatch(cap->nchar);
6338 		++curwin->w_cursor.col;
6339 	    }
6340 #ifdef FEAT_NETBEANS_INTG
6341 	    if (usingNetbeans)
6342 	    {
6343 		colnr_T start = (colnr_T)(curwin->w_cursor.col - cap->count1);
6344 
6345 		netbeans_inserted(curbuf, curwin->w_cursor.lnum, start,
6346 			     (int)cap->count1, &ptr[start], (int)cap->count1);
6347 	    }
6348 #endif
6349 
6350 	    /* mark the buffer as changed and prepare for displaying */
6351 	    changed_bytes(curwin->w_cursor.lnum,
6352 			       (colnr_T)(curwin->w_cursor.col - cap->count1));
6353 	}
6354 	--curwin->w_cursor.col;	    /* cursor on the last replaced char */
6355 #ifdef FEAT_MBYTE
6356 	/* if the character on the left of the current cursor is a multi-byte
6357 	 * character, move two characters left */
6358 	if (has_mbyte)
6359 	    mb_adjust_cursor();
6360 #endif
6361 	curbuf->b_op_end = curwin->w_cursor;
6362 	curwin->w_set_curswant = TRUE;
6363 	set_last_insert(cap->nchar);
6364     }
6365 }
6366 
6367 #ifdef FEAT_VISUAL
6368 /*
6369  * 'o': Exchange start and end of Visual area.
6370  * 'O': same, but in block mode exchange left and right corners.
6371  */
6372     static void
6373 v_swap_corners(cmdchar)
6374     int		cmdchar;
6375 {
6376     pos_T	old_cursor;
6377     colnr_T	left, right;
6378 
6379     if (cmdchar == 'O' && VIsual_mode == Ctrl_V)
6380     {
6381 	old_cursor = curwin->w_cursor;
6382 	getvcols(curwin, &old_cursor, &VIsual, &left, &right);
6383 	curwin->w_cursor.lnum = VIsual.lnum;
6384 	coladvance(left);
6385 	VIsual = curwin->w_cursor;
6386 
6387 	curwin->w_cursor.lnum = old_cursor.lnum;
6388 	curwin->w_curswant = right;
6389 	/* 'selection "exclusive" and cursor at right-bottom corner: move it
6390 	 * right one column */
6391 	if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e')
6392 	    ++curwin->w_curswant;
6393 	coladvance(curwin->w_curswant);
6394 	if (curwin->w_cursor.col == old_cursor.col
6395 #ifdef FEAT_VIRTUALEDIT
6396 		&& (!virtual_active()
6397 		    || curwin->w_cursor.coladd == old_cursor.coladd)
6398 #endif
6399 		)
6400 	{
6401 	    curwin->w_cursor.lnum = VIsual.lnum;
6402 	    if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e')
6403 		++right;
6404 	    coladvance(right);
6405 	    VIsual = curwin->w_cursor;
6406 
6407 	    curwin->w_cursor.lnum = old_cursor.lnum;
6408 	    coladvance(left);
6409 	    curwin->w_curswant = left;
6410 	}
6411     }
6412     else
6413     {
6414 	old_cursor = curwin->w_cursor;
6415 	curwin->w_cursor = VIsual;
6416 	VIsual = old_cursor;
6417 	curwin->w_set_curswant = TRUE;
6418     }
6419 }
6420 #endif /* FEAT_VISUAL */
6421 
6422 /*
6423  * "R" (cap->arg is FALSE) and "gR" (cap->arg is TRUE).
6424  */
6425     static void
6426 nv_Replace(cap)
6427     cmdarg_T	    *cap;
6428 {
6429 #ifdef FEAT_VISUAL
6430     if (VIsual_active)		/* "R" is replace lines */
6431     {
6432 	cap->cmdchar = 'c';
6433 	cap->nchar = NUL;
6434 	VIsual_mode = 'V';
6435 	nv_operator(cap);
6436     }
6437     else
6438 #endif
6439 	if (!checkclearopq(cap->oap))
6440     {
6441 	if (!curbuf->b_p_ma)
6442 	    EMSG(_(e_modifiable));
6443 	else
6444 	{
6445 #ifdef FEAT_VIRTUALEDIT
6446 	    if (virtual_active())
6447 		coladvance(getviscol());
6448 #endif
6449 	    invoke_edit(cap, FALSE, cap->arg ? 'V' : 'R', FALSE);
6450 	}
6451     }
6452 }
6453 
6454 #ifdef FEAT_VREPLACE
6455 /*
6456  * "gr".
6457  */
6458     static void
6459 nv_vreplace(cap)
6460     cmdarg_T	*cap;
6461 {
6462 # ifdef FEAT_VISUAL
6463     if (VIsual_active)
6464     {
6465 	cap->cmdchar = 'r';
6466 	cap->nchar = cap->extra_char;
6467 	nv_replace(cap);	/* Do same as "r" in Visual mode for now */
6468     }
6469     else
6470 # endif
6471 	if (!checkclearopq(cap->oap))
6472     {
6473 	if (!curbuf->b_p_ma)
6474 	    EMSG(_(e_modifiable));
6475 	else
6476 	{
6477 	    if (cap->extra_char == Ctrl_V)	/* get another character */
6478 		cap->extra_char = get_literal();
6479 	    stuffcharReadbuff(cap->extra_char);
6480 	    stuffcharReadbuff(ESC);
6481 # ifdef FEAT_VIRTUALEDIT
6482 	    if (virtual_active())
6483 		coladvance(getviscol());
6484 # endif
6485 	    invoke_edit(cap, TRUE, 'v', FALSE);
6486 	}
6487     }
6488 }
6489 #endif
6490 
6491 /*
6492  * Swap case for "~" command, when it does not work like an operator.
6493  */
6494     static void
6495 n_swapchar(cap)
6496     cmdarg_T	*cap;
6497 {
6498     long	n;
6499     pos_T	startpos;
6500     int		did_change = 0;
6501 #ifdef FEAT_NETBEANS_INTG
6502     pos_T	pos;
6503     char_u	*ptr;
6504     int		count;
6505 #endif
6506 
6507     if (checkclearopq(cap->oap))
6508 	return;
6509 
6510     if (lineempty(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL)
6511     {
6512 	clearopbeep(cap->oap);
6513 	return;
6514     }
6515 
6516     prep_redo_cmd(cap);
6517 
6518     if (u_save_cursor() == FAIL)
6519 	return;
6520 
6521     startpos = curwin->w_cursor;
6522 #ifdef FEAT_NETBEANS_INTG
6523     pos = startpos;
6524 #endif
6525     for (n = cap->count1; n > 0; --n)
6526     {
6527 	did_change |= swapchar(cap->oap->op_type, &curwin->w_cursor);
6528 	inc_cursor();
6529 	if (gchar_cursor() == NUL)
6530 	{
6531 	    if (vim_strchr(p_ww, '~') != NULL
6532 		    && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
6533 	    {
6534 #ifdef FEAT_NETBEANS_INTG
6535 		if (usingNetbeans)
6536 		{
6537 		    if (did_change)
6538 		    {
6539 			ptr = ml_get(pos.lnum);
6540 			count = STRLEN(ptr) - pos.col;
6541 			netbeans_inserted(curbuf, pos.lnum, pos.col,
6542 						 count, &ptr[pos.col], count);
6543 		    }
6544 		    pos.col = 0;
6545 		    pos.lnum++;
6546 		}
6547 #endif
6548 		++curwin->w_cursor.lnum;
6549 		curwin->w_cursor.col = 0;
6550 		if (n > 1)
6551 		{
6552 		    if (u_savesub(curwin->w_cursor.lnum) == FAIL)
6553 			break;
6554 		    u_clearline();
6555 		}
6556 	    }
6557 	    else
6558 		break;
6559 	}
6560     }
6561 #ifdef FEAT_NETBEANS_INTG
6562     if (did_change && usingNetbeans)
6563     {
6564 	ptr = ml_get(pos.lnum);
6565 	count = curwin->w_cursor.col - pos.col;
6566 	netbeans_inserted(curbuf, pos.lnum, pos.col,
6567 						 count, &ptr[pos.col], count);
6568     }
6569 #endif
6570 
6571 
6572     check_cursor();
6573     curwin->w_set_curswant = TRUE;
6574     if (did_change)
6575     {
6576 	changed_lines(startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1,
6577 									  0L);
6578 	curbuf->b_op_start = startpos;
6579 	curbuf->b_op_end = curwin->w_cursor;
6580 	if (curbuf->b_op_end.col > 0)
6581 	    --curbuf->b_op_end.col;
6582     }
6583 }
6584 
6585 /*
6586  * Move cursor to mark.
6587  */
6588     static void
6589 nv_cursormark(cap, flag, pos)
6590     cmdarg_T	*cap;
6591     int		flag;
6592     pos_T	*pos;
6593 {
6594     if (check_mark(pos) == FAIL)
6595 	clearop(cap->oap);
6596     else
6597     {
6598 	if (cap->cmdchar == '\''
6599 		|| cap->cmdchar == '`'
6600 		|| cap->cmdchar == '['
6601 		|| cap->cmdchar == ']')
6602 	    setpcmark();
6603 	curwin->w_cursor = *pos;
6604 	if (flag)
6605 	    beginline(BL_WHITE | BL_FIX);
6606 	else
6607 	    check_cursor();
6608     }
6609     cap->oap->motion_type = flag ? MLINE : MCHAR;
6610     if (cap->cmdchar == '`')
6611 	cap->oap->use_reg_one = TRUE;
6612     cap->oap->inclusive = FALSE;		/* ignored if not MCHAR */
6613     curwin->w_set_curswant = TRUE;
6614 }
6615 
6616 #ifdef FEAT_VISUAL
6617 /*
6618  * Handle commands that are operators in Visual mode.
6619  */
6620     static void
6621 v_visop(cap)
6622     cmdarg_T	*cap;
6623 {
6624     static char_u trans[] = "YyDdCcxdXdAAIIrr";
6625 
6626     /* Uppercase means linewise, except in block mode, then "D" deletes till
6627      * the end of the line, and "C" replaces til EOL */
6628     if (isupper(cap->cmdchar))
6629     {
6630 	if (VIsual_mode != Ctrl_V)
6631 	    VIsual_mode = 'V';
6632 	else if (cap->cmdchar == 'C' || cap->cmdchar == 'D')
6633 	    curwin->w_curswant = MAXCOL;
6634     }
6635     cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1);
6636     nv_operator(cap);
6637 }
6638 #endif
6639 
6640 /*
6641  * "s" and "S" commands.
6642  */
6643     static void
6644 nv_subst(cap)
6645     cmdarg_T	*cap;
6646 {
6647 #ifdef FEAT_VISUAL
6648     if (VIsual_active)	/* "vs" and "vS" are the same as "vc" */
6649     {
6650 	if (cap->cmdchar == 'S')
6651 	    VIsual_mode = 'V';
6652 	cap->cmdchar = 'c';
6653 	nv_operator(cap);
6654     }
6655     else
6656 #endif
6657 	nv_optrans(cap);
6658 }
6659 
6660 /*
6661  * Abbreviated commands.
6662  */
6663     static void
6664 nv_abbrev(cap)
6665     cmdarg_T	*cap;
6666 {
6667     if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL)
6668 	cap->cmdchar = 'x';		/* DEL key behaves like 'x' */
6669 
6670 #ifdef FEAT_VISUAL
6671     /* in Visual mode these commands are operators */
6672     if (VIsual_active)
6673 	v_visop(cap);
6674     else
6675 #endif
6676 	nv_optrans(cap);
6677 }
6678 
6679 /*
6680  * Translate a command into another command.
6681  */
6682     static void
6683 nv_optrans(cap)
6684     cmdarg_T	*cap;
6685 {
6686     static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
6687 			      (char_u *)"d$", (char_u *)"c$",
6688 			      (char_u *)"cl", (char_u *)"cc",
6689 			      (char_u *)"yy", (char_u *)":s\r"};
6690     static char_u *str = (char_u *)"xXDCsSY&";
6691 
6692     if (!checkclearopq(cap->oap))
6693     {
6694 	if (cap->count0)
6695 	    stuffnumReadbuff(cap->count0);
6696 	stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
6697     }
6698     cap->opcount = 0;
6699 }
6700 
6701 /*
6702  * "'" and "`" commands.  Also for "g'" and "g`".
6703  * cap->arg is TRUE for "'" and "g'".
6704  */
6705     static void
6706 nv_gomark(cap)
6707     cmdarg_T	*cap;
6708 {
6709     pos_T	*pos;
6710     int		c;
6711 #ifdef FEAT_FOLDING
6712     linenr_T	lnum = curwin->w_cursor.lnum;
6713     int		old_KeyTyped = KeyTyped;    /* getting file may reset it */
6714 #endif
6715 
6716     if (cap->cmdchar == 'g')
6717 	c = cap->extra_char;
6718     else
6719 	c = cap->nchar;
6720     pos = getmark(c, (cap->oap->op_type == OP_NOP));
6721     if (pos == (pos_T *)-1)	    /* jumped to other file */
6722     {
6723 	if (cap->arg)
6724 	{
6725 	    check_cursor_lnum();
6726 	    beginline(BL_WHITE | BL_FIX);
6727 	}
6728 	else
6729 	    check_cursor();
6730     }
6731     else
6732 	nv_cursormark(cap, cap->arg, pos);
6733 
6734 #ifdef FEAT_VIRTUALEDIT
6735     /* May need to clear the coladd that a mark includes. */
6736     if (!virtual_active())
6737 	curwin->w_cursor.coladd = 0;
6738 #endif
6739 #ifdef FEAT_FOLDING
6740     if (cap->oap->op_type == OP_NOP
6741 	    && (pos == (pos_T *)-1 || lnum != curwin->w_cursor.lnum)
6742 	    && (fdo_flags & FDO_MARK)
6743 	    && old_KeyTyped)
6744 	foldOpenCursor();
6745 #endif
6746 }
6747 
6748 /*
6749  * Handle CTRL-O, CTRL-I, "g;" and "g," commands.
6750  */
6751     static void
6752 nv_pcmark(cap)
6753     cmdarg_T	*cap;
6754 {
6755 #ifdef FEAT_JUMPLIST
6756     pos_T	*pos;
6757 # ifdef FEAT_FOLDING
6758     linenr_T	lnum = curwin->w_cursor.lnum;
6759     int		old_KeyTyped = KeyTyped;    /* getting file may reset it */
6760 # endif
6761 
6762     if (!checkclearopq(cap->oap))
6763     {
6764 	if (cap->cmdchar == 'g')
6765 	    pos = movechangelist((int)cap->count1);
6766 	else
6767 	    pos = movemark((int)cap->count1);
6768 	if (pos == (pos_T *)-1)		/* jump to other file */
6769 	{
6770 	    curwin->w_set_curswant = TRUE;
6771 	    check_cursor();
6772 	}
6773 	else if (pos != NULL)		    /* can jump */
6774 	    nv_cursormark(cap, FALSE, pos);
6775 	else if (cap->cmdchar == 'g')
6776 	{
6777 	    if (curbuf->b_changelistlen == 0)
6778 		EMSG(_("E664: changelist is empty"));
6779 	    else if (cap->count1 < 0)
6780 		EMSG(_("E662: At start of changelist"));
6781 	    else
6782 		EMSG(_("E663: At end of changelist"));
6783 	}
6784 	else
6785 	    clearopbeep(cap->oap);
6786 # ifdef FEAT_FOLDING
6787 	if (cap->oap->op_type == OP_NOP
6788 		&& (pos == (pos_T *)-1 || lnum != curwin->w_cursor.lnum)
6789 		&& (fdo_flags & FDO_MARK)
6790 		&& old_KeyTyped)
6791 	    foldOpenCursor();
6792 # endif
6793     }
6794 #else
6795     clearopbeep(cap->oap);
6796 #endif
6797 }
6798 
6799 /*
6800  * Handle '"' command.
6801  */
6802     static void
6803 nv_regname(cap)
6804     cmdarg_T	*cap;
6805 {
6806     if (checkclearop(cap->oap))
6807 	return;
6808 #ifdef FEAT_EVAL
6809     if (cap->nchar == '=')
6810 	cap->nchar = get_expr_register();
6811 #endif
6812     if (cap->nchar != NUL && valid_yank_reg(cap->nchar, FALSE))
6813     {
6814 	cap->oap->regname = cap->nchar;
6815 	cap->opcount = cap->count0;	/* remember count before '"' */
6816 #ifdef FEAT_EVAL
6817 	set_reg_var(cap->oap->regname);
6818 #endif
6819     }
6820     else
6821 	clearopbeep(cap->oap);
6822 }
6823 
6824 #ifdef FEAT_VISUAL
6825 /*
6826  * Handle "v", "V" and "CTRL-V" commands.
6827  * Also for "gh", "gH" and "g^H" commands: Always start Select mode, cap->arg
6828  * is TRUE.
6829  */
6830     static void
6831 nv_visual(cap)
6832     cmdarg_T	*cap;
6833 {
6834     /* 'v', 'V' and CTRL-V can be used while an operator is pending to make it
6835      * characterwise, linewise, or blockwise. */
6836     if (cap->oap->op_type != OP_NOP)
6837     {
6838 	cap->oap->motion_force = cap->cmdchar;
6839 	finish_op = FALSE;	/* operator doesn't finish now but later */
6840 	return;
6841     }
6842 
6843     VIsual_select = cap->arg;
6844     if (VIsual_active)	    /* change Visual mode */
6845     {
6846 	if (VIsual_mode == cap->cmdchar)    /* stop visual mode */
6847 	    end_visual_mode();
6848 	else				    /* toggle char/block mode */
6849 	{				    /*	   or char/line mode */
6850 	    VIsual_mode = cap->cmdchar;
6851 	    showmode();
6852 	}
6853 	redraw_curbuf_later(INVERTED);	    /* update the inversion */
6854     }
6855     else		    /* start Visual mode */
6856     {
6857 	check_visual_highlight();
6858 	if (cap->count0)		    /* use previously selected part */
6859 	{
6860 	    if (resel_VIsual_mode == NUL)   /* there is none */
6861 	    {
6862 		beep_flush();
6863 		return;
6864 	    }
6865 	    VIsual = curwin->w_cursor;
6866 
6867 	    VIsual_active = TRUE;
6868 	    VIsual_reselect = TRUE;
6869 	    if (!cap->arg)
6870 		/* start Select mode when 'selectmode' contains "cmd" */
6871 		may_start_select('c');
6872 #ifdef FEAT_MOUSE
6873 	    setmouse();
6874 #endif
6875 	    if (p_smd)
6876 		redraw_cmdline = TRUE;	    /* show visual mode later */
6877 	    /*
6878 	     * For V and ^V, we multiply the number of lines even if there
6879 	     * was only one -- webb
6880 	     */
6881 	    if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
6882 	    {
6883 		curwin->w_cursor.lnum +=
6884 				    resel_VIsual_line_count * cap->count0 - 1;
6885 		if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6886 		    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6887 	    }
6888 	    VIsual_mode = resel_VIsual_mode;
6889 	    if (VIsual_mode == 'v')
6890 	    {
6891 		if (resel_VIsual_line_count <= 1)
6892 		    curwin->w_cursor.col += resel_VIsual_col * cap->count0 - 1;
6893 		else
6894 		    curwin->w_cursor.col = resel_VIsual_col;
6895 		check_cursor_col();
6896 	    }
6897 	    if (resel_VIsual_col == MAXCOL)
6898 	    {
6899 		curwin->w_curswant = MAXCOL;
6900 		coladvance((colnr_T)MAXCOL);
6901 	    }
6902 	    else if (VIsual_mode == Ctrl_V)
6903 	    {
6904 		validate_virtcol();
6905 		curwin->w_curswant = curwin->w_virtcol
6906 					 + resel_VIsual_col * cap->count0 - 1;
6907 		coladvance(curwin->w_curswant);
6908 	    }
6909 	    else
6910 		curwin->w_set_curswant = TRUE;
6911 	    redraw_curbuf_later(INVERTED);	/* show the inversion */
6912 	}
6913 	else
6914 	{
6915 	    if (!cap->arg)
6916 		/* start Select mode when 'selectmode' contains "cmd" */
6917 		may_start_select('c');
6918 	    n_start_visual_mode(cap->cmdchar);
6919 	}
6920     }
6921 }
6922 
6923 /*
6924  * Start selection for Shift-movement keys.
6925  */
6926     void
6927 start_selection()
6928 {
6929     /* if 'selectmode' contains "key", start Select mode */
6930     may_start_select('k');
6931     n_start_visual_mode('v');
6932 }
6933 
6934 /*
6935  * Start Select mode, if "c" is in 'selectmode' and not in a mapping or menu.
6936  */
6937     void
6938 may_start_select(c)
6939     int		c;
6940 {
6941     VIsual_select = (stuff_empty() && typebuf_typed()
6942 		    && (vim_strchr(p_slm, c) != NULL));
6943 }
6944 
6945 /*
6946  * Start Visual mode "c".
6947  * Should set VIsual_select before calling this.
6948  */
6949     static void
6950 n_start_visual_mode(c)
6951     int		c;
6952 {
6953     VIsual_mode = c;
6954     VIsual_active = TRUE;
6955     VIsual_reselect = TRUE;
6956 #ifdef FEAT_VIRTUALEDIT
6957     /* Corner case: the 0 position in a tab may change when going into
6958      * virtualedit.  Recalculate curwin->w_cursor to avoid bad hilighting.
6959      */
6960     if (c == Ctrl_V && (ve_flags & VE_BLOCK) && gchar_cursor() == TAB)
6961 	coladvance(curwin->w_virtcol);
6962 #endif
6963     VIsual = curwin->w_cursor;
6964 
6965 #ifdef FEAT_FOLDING
6966     foldAdjustVisual();
6967 #endif
6968 
6969 #ifdef FEAT_MOUSE
6970     setmouse();
6971 #endif
6972     if (p_smd)
6973 	redraw_cmdline = TRUE;	/* show visual mode later */
6974 #ifdef FEAT_CLIPBOARD
6975     /* Make sure the clipboard gets updated.  Needed because start and
6976      * end may still be the same, and the selection needs to be owned */
6977     clip_star.vmode = NUL;
6978 #endif
6979 
6980     /* Only need to redraw this line, unless still need to redraw an old
6981      * Visual area (when 'lazyredraw' is set). */
6982     if (curwin->w_redr_type < INVERTED)
6983     {
6984 	curwin->w_old_cursor_lnum = curwin->w_cursor.lnum;
6985 	curwin->w_old_visual_lnum = curwin->w_cursor.lnum;
6986     }
6987 }
6988 
6989 #endif /* FEAT_VISUAL */
6990 
6991 /*
6992  * CTRL-W: Window commands
6993  */
6994     static void
6995 nv_window(cap)
6996     cmdarg_T	*cap;
6997 {
6998 #ifdef FEAT_WINDOWS
6999     if (!checkclearop(cap->oap))
7000 	do_window(cap->nchar, cap->count0, NUL); /* everything is in window.c */
7001 #else
7002     (void)checkclearop(cap->oap);
7003 #endif
7004 }
7005 
7006 /*
7007  * CTRL-Z: Suspend
7008  */
7009     static void
7010 nv_suspend(cap)
7011     cmdarg_T	*cap;
7012 {
7013     clearop(cap->oap);
7014 #ifdef FEAT_VISUAL
7015     if (VIsual_active)
7016 	end_visual_mode();		/* stop Visual mode */
7017 #endif
7018     do_cmdline_cmd((char_u *)"st");
7019 }
7020 
7021 /*
7022  * Commands starting with "g".
7023  */
7024     static void
7025 nv_g_cmd(cap)
7026     cmdarg_T	*cap;
7027 {
7028     oparg_T	*oap = cap->oap;
7029 #ifdef FEAT_VISUAL
7030     pos_T	tpos;
7031 #endif
7032     int		i;
7033     int		flag = FALSE;
7034 
7035     switch (cap->nchar)
7036     {
7037 #ifdef MEM_PROFILE
7038     /*
7039      * "g^A": dump log of used memory.
7040      */
7041     case Ctrl_A:
7042 	vim_mem_profile_dump();
7043 	break;
7044 #endif
7045 
7046 #ifdef FEAT_VREPLACE
7047     /*
7048      * "gR": Enter virtual replace mode.
7049      */
7050     case 'R':
7051 	cap->arg = TRUE;
7052 	nv_Replace(cap);
7053 	break;
7054 
7055     case 'r':
7056 	nv_vreplace(cap);
7057 	break;
7058 #endif
7059 
7060     case '&':
7061 	do_cmdline_cmd((char_u *)"%s//~/&");
7062 	break;
7063 
7064 #ifdef FEAT_VISUAL
7065     /*
7066      * "gv": Reselect the previous Visual area.  If Visual already active,
7067      *	     exchange previous and current Visual area.
7068      */
7069     case 'v':
7070 	if (checkclearop(oap))
7071 	    break;
7072 
7073 	if (	   curbuf->b_visual_start.lnum == 0
7074 		|| curbuf->b_visual_start.lnum > curbuf->b_ml.ml_line_count
7075 		|| curbuf->b_visual_end.lnum == 0)
7076 	    beep_flush();
7077 	else
7078 	{
7079 	    /* set w_cursor to the start of the Visual area, tpos to the end */
7080 	    if (VIsual_active)
7081 	    {
7082 		i = VIsual_mode;
7083 		VIsual_mode = curbuf->b_visual_mode;
7084 		curbuf->b_visual_mode = i;
7085 # ifdef FEAT_EVAL
7086 		curbuf->b_visual_mode_eval = i;
7087 # endif
7088 		i = curwin->w_curswant;
7089 		curwin->w_curswant = curbuf->b_visual_curswant;
7090 		curbuf->b_visual_curswant = i;
7091 
7092 		tpos = curbuf->b_visual_end;
7093 		curbuf->b_visual_end = curwin->w_cursor;
7094 		curwin->w_cursor = curbuf->b_visual_start;
7095 		curbuf->b_visual_start = VIsual;
7096 	    }
7097 	    else
7098 	    {
7099 		VIsual_mode = curbuf->b_visual_mode;
7100 		curwin->w_curswant = curbuf->b_visual_curswant;
7101 		tpos = curbuf->b_visual_end;
7102 		curwin->w_cursor = curbuf->b_visual_start;
7103 	    }
7104 
7105 	    VIsual_active = TRUE;
7106 	    VIsual_reselect = TRUE;
7107 
7108 	    /* Set Visual to the start and w_cursor to the end of the Visual
7109 	     * area.  Make sure they are on an existing character. */
7110 	    check_cursor();
7111 	    VIsual = curwin->w_cursor;
7112 	    curwin->w_cursor = tpos;
7113 	    check_cursor();
7114 	    update_topline();
7115 	    /*
7116 	     * When called from normal "g" command: start Select mode when
7117 	     * 'selectmode' contains "cmd".  When called for K_SELECT, always
7118 	     * start Select mode.
7119 	     */
7120 	    if (cap->arg)
7121 		VIsual_select = TRUE;
7122 	    else
7123 		may_start_select('c');
7124 #ifdef FEAT_MOUSE
7125 	    setmouse();
7126 #endif
7127 #ifdef FEAT_CLIPBOARD
7128 	    /* Make sure the clipboard gets updated.  Needed because start and
7129 	     * end are still the same, and the selection needs to be owned */
7130 	    clip_star.vmode = NUL;
7131 #endif
7132 	    redraw_curbuf_later(INVERTED);
7133 	    showmode();
7134 	}
7135 	break;
7136     /*
7137      * "gV": Don't reselect the previous Visual area after a Select mode
7138      *	     mapping of menu.
7139      */
7140     case 'V':
7141 	VIsual_reselect = FALSE;
7142 	break;
7143 
7144     /*
7145      * "gh":  start Select mode.
7146      * "gH":  start Select line mode.
7147      * "g^H": start Select block mode.
7148      */
7149     case K_BS:
7150 	cap->nchar = Ctrl_H;
7151 	/* FALLTHROUGH */
7152     case 'h':
7153     case 'H':
7154     case Ctrl_H:
7155 # ifdef EBCDIC
7156 	/* EBCDIC: 'v'-'h' != '^v'-'^h' */
7157 	if (cap->nchar == Ctrl_H)
7158 	    cap->cmdchar = Ctrl_V;
7159 	else
7160 # endif
7161 	cap->cmdchar = cap->nchar + ('v' - 'h');
7162 	cap->arg = TRUE;
7163 	nv_visual(cap);
7164 	break;
7165 #endif /* FEAT_VISUAL */
7166 
7167     /*
7168      * "gj" and "gk" two new funny movement keys -- up and down
7169      * movement based on *screen* line rather than *file* line.
7170      */
7171     case 'j':
7172     case K_DOWN:
7173 	/* with 'nowrap' it works just like the normal "j" command; also when
7174 	 * in a closed fold */
7175 	if (!curwin->w_p_wrap
7176 #ifdef FEAT_FOLDING
7177 		|| hasFolding(curwin->w_cursor.lnum, NULL, NULL)
7178 #endif
7179 		)
7180 	{
7181 	    oap->motion_type = MLINE;
7182 	    i = cursor_down(cap->count1, oap->op_type == OP_NOP);
7183 	}
7184 	else
7185 	    i = nv_screengo(oap, FORWARD, cap->count1);
7186 	if (i == FAIL)
7187 	    clearopbeep(oap);
7188 	break;
7189 
7190     case 'k':
7191     case K_UP:
7192 	/* with 'nowrap' it works just like the normal "k" command; also when
7193 	 * in a closed fold */
7194 	if (!curwin->w_p_wrap
7195 #ifdef FEAT_FOLDING
7196 		|| hasFolding(curwin->w_cursor.lnum, NULL, NULL)
7197 #endif
7198 	   )
7199 	{
7200 	    oap->motion_type = MLINE;
7201 	    i = cursor_up(cap->count1, oap->op_type == OP_NOP);
7202 	}
7203 	else
7204 	    i = nv_screengo(oap, BACKWARD, cap->count1);
7205 	if (i == FAIL)
7206 	    clearopbeep(oap);
7207 	break;
7208 
7209     /*
7210      * "gJ": join two lines without inserting a space.
7211      */
7212     case 'J':
7213 	nv_join(cap);
7214 	break;
7215 
7216     /*
7217      * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
7218      * "gm": middle of "g0" and "g$".
7219      */
7220     case '^':
7221 	flag = TRUE;
7222 	/* FALLTHROUGH */
7223 
7224     case '0':
7225     case 'm':
7226     case K_HOME:
7227     case K_KHOME:
7228     case K_XHOME:
7229 	oap->motion_type = MCHAR;
7230 	oap->inclusive = FALSE;
7231 	if (curwin->w_p_wrap
7232 #ifdef FEAT_VERTSPLIT
7233 		&& curwin->w_width != 0
7234 #endif
7235 		)
7236 	{
7237 	    int		width1 = W_WIDTH(curwin) - curwin_col_off();
7238 	    int		width2 = width1 + curwin_col_off2();
7239 
7240 	    validate_virtcol();
7241 	    i = 0;
7242 	    if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0)
7243 		i = (curwin->w_virtcol - width1) / width2 * width2 + width1;
7244 	}
7245 	else
7246 	    i = curwin->w_leftcol;
7247 	/* Go to the middle of the screen line.  When 'number' is on and lines
7248 	 * are wrapping the middle can be more to the left.*/
7249 	if (cap->nchar == 'm')
7250 	    i += (W_WIDTH(curwin) - curwin_col_off()
7251 		    + ((curwin->w_p_wrap && i > 0)
7252 			? curwin_col_off2() : 0)) / 2;
7253 	coladvance((colnr_T)i);
7254 	if (flag)
7255 	{
7256 	    do
7257 		i = gchar_cursor();
7258 	    while (vim_iswhite(i) && oneright() == OK);
7259 	}
7260 	curwin->w_set_curswant = TRUE;
7261 	break;
7262 
7263     case '_':
7264 	/* "g_": to the last non-blank character in the line or <count> lines
7265 	 * downward. */
7266 	cap->oap->motion_type = MCHAR;
7267 	cap->oap->inclusive = TRUE;
7268 	curwin->w_curswant = MAXCOL;
7269 	if (cursor_down((long)(cap->count1 - 1),
7270 					 cap->oap->op_type == OP_NOP) == FAIL)
7271 	    clearopbeep(cap->oap);
7272 	else
7273 	{
7274 	    char_u  *ptr = ml_get_curline();
7275 
7276 	    /* In Visual mode we may end up after the line. */
7277 	    if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL)
7278 		--curwin->w_cursor.col;
7279 
7280 	    /* Decrease the cursor column until it's on a non-blank. */
7281 	    while (curwin->w_cursor.col > 0
7282 				    && vim_iswhite(ptr[curwin->w_cursor.col]))
7283 		--curwin->w_cursor.col;
7284 	    curwin->w_set_curswant = TRUE;
7285 	}
7286 	break;
7287 
7288     case '$':
7289     case K_END:
7290     case K_KEND:
7291     case K_XEND:
7292 	{
7293 	    int col_off = curwin_col_off();
7294 
7295 	    oap->motion_type = MCHAR;
7296 	    oap->inclusive = TRUE;
7297 	    if (curwin->w_p_wrap
7298 #ifdef FEAT_VERTSPLIT
7299 		    && curwin->w_width != 0
7300 #endif
7301 	       )
7302 	    {
7303 		curwin->w_curswant = MAXCOL;    /* so we stay at the end */
7304 		if (cap->count1 == 1)
7305 		{
7306 		    int		width1 = W_WIDTH(curwin) - col_off;
7307 		    int		width2 = width1 + curwin_col_off2();
7308 
7309 		    validate_virtcol();
7310 		    i = width1 - 1;
7311 		    if (curwin->w_virtcol >= (colnr_T)width1)
7312 			i += ((curwin->w_virtcol - width1) / width2 + 1)
7313 								     * width2;
7314 		    coladvance((colnr_T)i);
7315 #if defined(FEAT_LINEBREAK) || defined(FEAT_MBYTE)
7316 		    if (curwin->w_cursor.col > 0 && curwin->w_p_wrap)
7317 		    {
7318 			/*
7319 			 * Check for landing on a character that got split at
7320 			 * the end of the line.  We do not want to advance to
7321 			 * the next screen line.
7322 			 */
7323 			validate_virtcol();
7324 			if (curwin->w_virtcol > (colnr_T)i)
7325 			    --curwin->w_cursor.col;
7326 		    }
7327 #endif
7328 		}
7329 		else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL)
7330 		    clearopbeep(oap);
7331 	    }
7332 	    else
7333 	    {
7334 		i = curwin->w_leftcol + W_WIDTH(curwin) - col_off - 1;
7335 		coladvance((colnr_T)i);
7336 		curwin->w_set_curswant = TRUE;
7337 	    }
7338 	}
7339 	break;
7340 
7341     /*
7342      * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
7343      */
7344     case '*':
7345     case '#':
7346 #if POUND != '#'
7347     case POUND:		/* pound sign (sometimes equal to '#') */
7348 #endif
7349     case Ctrl_RSB:		/* :tag or :tselect for current identifier */
7350     case ']':			/* :tselect for current identifier */
7351 	nv_ident(cap);
7352 	break;
7353 
7354     /*
7355      * ge and gE: go back to end of word
7356      */
7357     case 'e':
7358     case 'E':
7359 	oap->motion_type = MCHAR;
7360 	curwin->w_set_curswant = TRUE;
7361 	oap->inclusive = TRUE;
7362 	if (bckend_word(cap->count1, cap->nchar == 'E', FALSE) == FAIL)
7363 	    clearopbeep(oap);
7364 	break;
7365 
7366     /*
7367      * "g CTRL-G": display info about cursor position
7368      */
7369     case Ctrl_G:
7370 	cursor_pos_info();
7371 	break;
7372 
7373     /*
7374      * "gi": start Insert at the last position.
7375      */
7376     case 'i':
7377 	if (curbuf->b_last_insert.lnum != 0)
7378 	{
7379 	    curwin->w_cursor = curbuf->b_last_insert;
7380 	    check_cursor_lnum();
7381 	    i = (int)STRLEN(ml_get_curline());
7382 	    if (curwin->w_cursor.col > (colnr_T)i)
7383 	    {
7384 #ifdef FEAT_VIRTUALEDIT
7385 		if (virtual_active())
7386 		    curwin->w_cursor.coladd += curwin->w_cursor.col - i;
7387 #endif
7388 		curwin->w_cursor.col = i;
7389 	    }
7390 	}
7391 	cap->cmdchar = 'i';
7392 	nv_edit(cap);
7393 	break;
7394 
7395     /*
7396      * "gI": Start insert in column 1.
7397      */
7398     case 'I':
7399 	beginline(0);
7400 	if (!checkclearopq(oap))
7401 	    invoke_edit(cap, FALSE, 'g', FALSE);
7402 	break;
7403 
7404 #ifdef FEAT_SEARCHPATH
7405     /*
7406      * "gf": goto file, edit file under cursor
7407      * "]f" and "[f": can also be used.
7408      */
7409     case 'f':
7410 	nv_gotofile(cap);
7411 	break;
7412 #endif
7413 
7414 	/* "g'm" and "g`m": jump to mark without setting pcmark */
7415     case '\'':
7416 	cap->arg = TRUE;
7417 	/*FALLTHROUGH*/
7418     case '`':
7419 	nv_gomark(cap);
7420 	break;
7421 
7422     /*
7423      * "gs": Goto sleep.
7424      */
7425     case 's':
7426 	do_sleep(cap->count1 * 1000L);
7427 	break;
7428 
7429     /*
7430      * "ga": Display the ascii value of the character under the
7431      * cursor.	It is displayed in decimal, hex, and octal. -- webb
7432      */
7433     case 'a':
7434 	do_ascii(NULL);
7435 	break;
7436 
7437 #ifdef FEAT_MBYTE
7438     /*
7439      * "g8": Display the bytes used for the UTF-8 character under the
7440      * cursor.	It is displayed in hex.
7441      */
7442     case '8':
7443 	show_utf8();
7444 	break;
7445 #endif
7446 
7447     /*
7448      * "gg": Goto the first line in file.  With a count it goes to
7449      * that line number like for "G". -- webb
7450      */
7451     case 'g':
7452 	cap->arg = FALSE;
7453 	nv_goto(cap);
7454 	break;
7455 
7456     /*
7457      *	 Two-character operators:
7458      *	 "gq"	    Format text
7459      *	 "gw"	    Format text and keep cursor position
7460      *	 "g~"	    Toggle the case of the text.
7461      *	 "gu"	    Change text to lower case.
7462      *	 "gU"	    Change text to upper case.
7463      *   "g?"	    rot13 encoding
7464      */
7465     case 'q':
7466     case 'w':
7467 	oap->cursor_start = curwin->w_cursor;
7468 	/*FALLTHROUGH*/
7469     case '~':
7470     case 'u':
7471     case 'U':
7472     case '?':
7473 	nv_operator(cap);
7474 	break;
7475 
7476     /*
7477      * "gd": Find first occurence of pattern under the cursor in the
7478      *	 current function
7479      * "gD": idem, but in the current file.
7480      */
7481     case 'd':
7482     case 'D':
7483 	nv_gd(oap, cap->nchar);
7484 	break;
7485 
7486 #ifdef FEAT_MOUSE
7487     /*
7488      * g<*Mouse> : <C-*mouse>
7489      */
7490     case K_MIDDLEMOUSE:
7491     case K_MIDDLEDRAG:
7492     case K_MIDDLERELEASE:
7493     case K_LEFTMOUSE:
7494     case K_LEFTDRAG:
7495     case K_LEFTRELEASE:
7496     case K_RIGHTMOUSE:
7497     case K_RIGHTDRAG:
7498     case K_RIGHTRELEASE:
7499     case K_X1MOUSE:
7500     case K_X1DRAG:
7501     case K_X1RELEASE:
7502     case K_X2MOUSE:
7503     case K_X2DRAG:
7504     case K_X2RELEASE:
7505 	mod_mask = MOD_MASK_CTRL;
7506 	(void)do_mouse(oap, cap->nchar, BACKWARD, cap->count1, 0);
7507 	break;
7508 #endif
7509 
7510     case K_IGNORE:
7511 	break;
7512 
7513     /*
7514      * "gP" and "gp": same as "P" and "p" but leave cursor just after new text
7515      */
7516     case 'p':
7517     case 'P':
7518 	nv_put(cap);
7519 	break;
7520 
7521 #ifdef FEAT_BYTEOFF
7522     /* "go": goto byte count from start of buffer */
7523     case 'o':
7524 	goto_byte(cap->count0);
7525 	break;
7526 #endif
7527 
7528     /* "gQ": improved Ex mode */
7529     case 'Q':
7530 #ifdef FEAT_CMDWIN
7531 	if (cmdwin_type != 0)
7532 	{
7533 	    clearopbeep(cap->oap);
7534 	    break;
7535 	}
7536 #endif
7537 	if (!checkclearopq(oap))
7538 	    do_exmode(TRUE);
7539 	break;
7540 
7541 #ifdef FEAT_JUMPLIST
7542     case ',':
7543 	nv_pcmark(cap);
7544 	break;
7545 
7546     case ';':
7547 	cap->count1 = -cap->count1;
7548 	nv_pcmark(cap);
7549 	break;
7550 #endif
7551 
7552     default:
7553 	clearopbeep(oap);
7554 	break;
7555     }
7556 }
7557 
7558 /*
7559  * Handle "o" and "O" commands.
7560  */
7561     static void
7562 n_opencmd(cap)
7563     cmdarg_T	*cap;
7564 {
7565     if (!checkclearopq(cap->oap))
7566     {
7567 #ifdef FEAT_FOLDING
7568 	if (cap->cmdchar == 'O')
7569 	    /* Open above the first line of a folded sequence of lines */
7570 	    (void)hasFolding(curwin->w_cursor.lnum,
7571 						&curwin->w_cursor.lnum, NULL);
7572 	else
7573 	    /* Open below the last line of a folded sequence of lines */
7574 	    (void)hasFolding(curwin->w_cursor.lnum,
7575 						NULL, &curwin->w_cursor.lnum);
7576 #endif
7577 	if (u_save((linenr_T)(curwin->w_cursor.lnum -
7578 					       (cap->cmdchar == 'O' ? 1 : 0)),
7579 		   (linenr_T)(curwin->w_cursor.lnum +
7580 					       (cap->cmdchar == 'o' ? 1 : 0))
7581 		       ) == OK
7582 		&& open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
7583 #ifdef FEAT_COMMENTS
7584 		    has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM :
7585 #endif
7586 		    0, 0))
7587 	{
7588 	    invoke_edit(cap, FALSE, cap->cmdchar, TRUE);
7589 	}
7590     }
7591 }
7592 
7593 /*
7594  * "." command: redo last change.
7595  */
7596     static void
7597 nv_dot(cap)
7598     cmdarg_T	*cap;
7599 {
7600     if (!checkclearopq(cap->oap))
7601     {
7602 	/*
7603 	 * If "restart_edit" is TRUE, the last but one command is repeated
7604 	 * instead of the last command (inserting text). This is used for
7605 	 * CTRL-O <.> in insert mode.
7606 	 */
7607 	if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == FAIL)
7608 	    clearopbeep(cap->oap);
7609     }
7610 }
7611 
7612 /*
7613  * CTRL-R: undo undo
7614  */
7615     static void
7616 nv_redo(cap)
7617     cmdarg_T	*cap;
7618 {
7619     if (!checkclearopq(cap->oap))
7620     {
7621 	u_redo((int)cap->count1);
7622 	curwin->w_set_curswant = TRUE;
7623     }
7624 }
7625 
7626 /*
7627  * Handle "U" command.
7628  */
7629     static void
7630 nv_Undo(cap)
7631     cmdarg_T	*cap;
7632 {
7633     /* In Visual mode and typing "gUU" triggers an operator */
7634     if (cap->oap->op_type == OP_UPPER
7635 #ifdef FEAT_VISUAL
7636 	    || VIsual_active
7637 #endif
7638 	    )
7639     {
7640 	/* translate "gUU" to "gUgU" */
7641 	cap->cmdchar = 'g';
7642 	cap->nchar = 'U';
7643 	nv_operator(cap);
7644     }
7645     else if (!checkclearopq(cap->oap))
7646     {
7647 	u_undoline();
7648 	curwin->w_set_curswant = TRUE;
7649     }
7650 }
7651 
7652 /*
7653  * '~' command: If tilde is not an operator and Visual is off: swap case of a
7654  * single character.
7655  */
7656     static void
7657 nv_tilde(cap)
7658     cmdarg_T	*cap;
7659 {
7660     if (!p_to
7661 #ifdef FEAT_VISUAL
7662 	    && !VIsual_active
7663 #endif
7664 	    && cap->oap->op_type != OP_TILDE)
7665 	n_swapchar(cap);
7666     else
7667 	nv_operator(cap);
7668 }
7669 
7670 /*
7671  * Handle an operator command.
7672  * The actual work is done by do_pending_operator().
7673  */
7674     static void
7675 nv_operator(cap)
7676     cmdarg_T	*cap;
7677 {
7678     int	    op_type;
7679 
7680     op_type = get_op_type(cap->cmdchar, cap->nchar);
7681 
7682     if (op_type == cap->oap->op_type)	    /* double operator works on lines */
7683 	nv_lineop(cap);
7684     else if (!checkclearop(cap->oap))
7685     {
7686 	cap->oap->start = curwin->w_cursor;
7687 	cap->oap->op_type = op_type;
7688     }
7689 }
7690 
7691 /*
7692  * Handle linewise operator "dd", "yy", etc.
7693  *
7694  * "_" is is a strange motion command that helps make operators more logical.
7695  * It is actually implemented, but not documented in the real Vi.  This motion
7696  * command actually refers to "the current line".  Commands like "dd" and "yy"
7697  * are really an alternate form of "d_" and "y_".  It does accept a count, so
7698  * "d3_" works to delete 3 lines.
7699  */
7700     static void
7701 nv_lineop(cap)
7702     cmdarg_T	*cap;
7703 {
7704     cap->oap->motion_type = MLINE;
7705     if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL)
7706 	clearopbeep(cap->oap);
7707     else if (  cap->oap->op_type == OP_DELETE
7708 	    || cap->oap->op_type == OP_LSHIFT
7709 	    || cap->oap->op_type == OP_RSHIFT)
7710 	beginline(BL_SOL | BL_FIX);
7711     else if (cap->oap->op_type != OP_YANK)	/* 'Y' does not move cursor */
7712 	beginline(BL_WHITE | BL_FIX);
7713 }
7714 
7715 /*
7716  * <Home> command.
7717  */
7718     static void
7719 nv_home(cap)
7720     cmdarg_T	*cap;
7721 {
7722     cap->count0 = 1;
7723     nv_pipe(cap);
7724 }
7725 
7726 /*
7727  * "|" command.
7728  */
7729     static void
7730 nv_pipe(cap)
7731     cmdarg_T *cap;
7732 {
7733     cap->oap->motion_type = MCHAR;
7734     cap->oap->inclusive = FALSE;
7735     beginline(0);
7736     if (cap->count0 > 0)
7737     {
7738 	coladvance((colnr_T)(cap->count0 - 1));
7739 	curwin->w_curswant = (colnr_T)(cap->count0 - 1);
7740     }
7741     else
7742 	curwin->w_curswant = 0;
7743     /* keep curswant at the column where we wanted to go, not where
7744        we ended; differs if line is too short */
7745     curwin->w_set_curswant = FALSE;
7746 }
7747 
7748 /*
7749  * Handle back-word command "b" and "B".
7750  * cap->arg is 1 for "B"
7751  */
7752     static void
7753 nv_bck_word(cap)
7754     cmdarg_T	*cap;
7755 {
7756     cap->oap->motion_type = MCHAR;
7757     cap->oap->inclusive = FALSE;
7758     curwin->w_set_curswant = TRUE;
7759     if (bck_word(cap->count1, cap->arg, FALSE) == FAIL)
7760 	clearopbeep(cap->oap);
7761 #ifdef FEAT_FOLDING
7762     else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
7763 	foldOpenCursor();
7764 #endif
7765 }
7766 
7767 /*
7768  * Handle word motion commands "e", "E", "w" and "W".
7769  * cap->arg is TRUE for "E" and "W".
7770  */
7771     static void
7772 nv_wordcmd(cap)
7773     cmdarg_T	*cap;
7774 {
7775     int		n;
7776     int		word_end;
7777     int		flag = FALSE;
7778 
7779     /*
7780      * Set inclusive for the "E" and "e" command.
7781      */
7782     if (cap->cmdchar == 'e' || cap->cmdchar == 'E')
7783 	word_end = TRUE;
7784     else
7785 	word_end = FALSE;
7786     cap->oap->inclusive = word_end;
7787 
7788     /*
7789      * "cw" and "cW" are a special case.
7790      */
7791     if (!word_end && cap->oap->op_type == OP_CHANGE)
7792     {
7793 	n = gchar_cursor();
7794 	if (n != NUL)			/* not an empty line */
7795 	{
7796 	    if (vim_iswhite(n))
7797 	    {
7798 		/*
7799 		 * Reproduce a funny Vi behaviour: "cw" on a blank only
7800 		 * changes one character, not all blanks until the start of
7801 		 * the next word.  Only do this when the 'w' flag is included
7802 		 * in 'cpoptions'.
7803 		 */
7804 		if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
7805 		{
7806 		    cap->oap->inclusive = TRUE;
7807 		    cap->oap->motion_type = MCHAR;
7808 		    return;
7809 		}
7810 	    }
7811 	    else
7812 	    {
7813 		/*
7814 		 * This is a little strange. To match what the real Vi does,
7815 		 * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
7816 		 * that we are not on a space or a TAB.  This seems impolite
7817 		 * at first, but it's really more what we mean when we say
7818 		 * 'cw'.
7819 		 * Another strangeness: When standing on the end of a word
7820 		 * "ce" will change until the end of the next wordt, but "cw"
7821 		 * will change only one character! This is done by setting
7822 		 * flag.
7823 		 */
7824 		cap->oap->inclusive = TRUE;
7825 		word_end = TRUE;
7826 		flag = TRUE;
7827 	    }
7828 	}
7829     }
7830 
7831     cap->oap->motion_type = MCHAR;
7832     curwin->w_set_curswant = TRUE;
7833     if (word_end)
7834 	n = end_word(cap->count1, cap->arg, flag, FALSE);
7835     else
7836 	n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP);
7837 
7838     /* Don't leave the cursor on the NUL past a line */
7839     if (curwin->w_cursor.col && gchar_cursor() == NUL)
7840     {
7841 	--curwin->w_cursor.col;
7842 	cap->oap->inclusive = TRUE;
7843     }
7844 
7845     if (n == FAIL && cap->oap->op_type == OP_NOP)
7846 	clearopbeep(cap->oap);
7847     else
7848     {
7849 #ifdef FEAT_VISUAL
7850 	adjust_for_sel(cap);
7851 #endif
7852 #ifdef FEAT_FOLDING
7853 	if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
7854 	    foldOpenCursor();
7855 #endif
7856     }
7857 }
7858 
7859 /*
7860  * "0" and "^" commands.
7861  * cap->arg is the argument for beginline().
7862  */
7863     static void
7864 nv_beginline(cap)
7865     cmdarg_T	*cap;
7866 {
7867     cap->oap->motion_type = MCHAR;
7868     cap->oap->inclusive = FALSE;
7869     beginline(cap->arg);
7870 #ifdef FEAT_FOLDING
7871     if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
7872 	foldOpenCursor();
7873 #endif
7874 }
7875 
7876 #ifdef FEAT_VISUAL
7877 /*
7878  * In exclusive Visual mode, may include the last character.
7879  */
7880     static void
7881 adjust_for_sel(cap)
7882     cmdarg_T	*cap;
7883 {
7884     if (VIsual_active && cap->oap->inclusive && *p_sel == 'e'
7885 	    && gchar_cursor() != NUL && lt(VIsual, curwin->w_cursor))
7886     {
7887 # ifdef FEAT_MBYTE
7888 	if (has_mbyte)
7889 	    inc_cursor();
7890 	else
7891 # endif
7892 	    ++curwin->w_cursor.col;
7893 	cap->oap->inclusive = FALSE;
7894     }
7895 }
7896 
7897 /*
7898  * Exclude last character at end of Visual area for 'selection' == "exclusive".
7899  * Should check VIsual_mode before calling this.
7900  * Returns TRUE when backed up to the previous line.
7901  */
7902     static int
7903 unadjust_for_sel()
7904 {
7905     pos_T	*pp;
7906 
7907     if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor))
7908     {
7909 	if (lt(VIsual, curwin->w_cursor))
7910 	    pp = &curwin->w_cursor;
7911 	else
7912 	    pp = &VIsual;
7913 #ifdef FEAT_VIRTUALEDIT
7914 	if (pp->coladd > 0)
7915 	    --pp->coladd;
7916 	else
7917 #endif
7918 	if (pp->col > 0)
7919 	{
7920 	    --pp->col;
7921 #ifdef FEAT_MBYTE
7922 	    mb_adjustpos(pp);
7923 #endif
7924 	}
7925 	else if (pp->lnum > 1)
7926 	{
7927 	    --pp->lnum;
7928 	    pp->col = (colnr_T)STRLEN(ml_get(pp->lnum));
7929 	    return TRUE;
7930 	}
7931     }
7932     return FALSE;
7933 }
7934 
7935 /*
7936  * SELECT key in Normal or Visual mode: end of Select mode mapping.
7937  */
7938     static void
7939 nv_select(cap)
7940     cmdarg_T	*cap;
7941 {
7942     if (VIsual_active)
7943 	VIsual_select = TRUE;
7944     else if (VIsual_reselect)
7945     {
7946 	cap->nchar = 'v';	    /* fake "gv" command */
7947 	cap->arg = TRUE;
7948 	nv_g_cmd(cap);
7949     }
7950 }
7951 
7952 #endif
7953 
7954 /*
7955  * "G", "gg", CTRL-END, CTRL-HOME.
7956  * cap->arg is TRUE for "G".
7957  */
7958     static void
7959 nv_goto(cap)
7960     cmdarg_T	*cap;
7961 {
7962     linenr_T	lnum;
7963 
7964     if (cap->arg)
7965 	lnum = curbuf->b_ml.ml_line_count;
7966     else
7967 	lnum = 1L;
7968     cap->oap->motion_type = MLINE;
7969     setpcmark();
7970 
7971     /* When a count is given, use it instead of the default lnum */
7972     if (cap->count0 != 0)
7973 	lnum = cap->count0;
7974     if (lnum < 1L)
7975 	lnum = 1L;
7976     else if (lnum > curbuf->b_ml.ml_line_count)
7977 	lnum = curbuf->b_ml.ml_line_count;
7978     curwin->w_cursor.lnum = lnum;
7979     beginline(BL_SOL | BL_FIX);
7980 #ifdef FEAT_FOLDING
7981     if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP)
7982 	foldOpenCursor();
7983 #endif
7984 }
7985 
7986 /*
7987  * CTRL-\ in Normal mode.
7988  */
7989     static void
7990 nv_normal(cap)
7991     cmdarg_T	*cap;
7992 {
7993     if (cap->nchar == Ctrl_N || cap->nchar == Ctrl_G)
7994     {
7995 	clearop(cap->oap);
7996 	if (restart_edit != 0 && p_smd)
7997 	    clear_cmdline = TRUE;		/* unshow mode later */
7998 	restart_edit = 0;
7999 #ifdef FEAT_CMDWIN
8000 	if (cmdwin_type != 0)
8001 	    cmdwin_result = Ctrl_C;
8002 #endif
8003 #ifdef FEAT_VISUAL
8004 	if (VIsual_active)
8005 	{
8006 	    end_visual_mode();		/* stop Visual */
8007 	    redraw_curbuf_later(INVERTED);
8008 	}
8009 #endif
8010 	/* CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set. */
8011 	if (cap->nchar == Ctrl_G && p_im)
8012 	    restart_edit = 'a';
8013     }
8014     else
8015 	clearopbeep(cap->oap);
8016 }
8017 
8018 /*
8019  * ESC in Normal mode: beep, but don't flush buffers.
8020  * Don't even beep if we are canceling a command.
8021  */
8022     static void
8023 nv_esc(cap)
8024     cmdarg_T	*cap;
8025 {
8026     int		no_reason;
8027 
8028     no_reason = (cap->oap->op_type == OP_NOP
8029 		&& cap->opcount == 0
8030 		&& cap->count0 == 0
8031 		&& cap->oap->regname == 0
8032 		&& !p_im);
8033 
8034     if (cap->arg)		/* TRUE for CTRL-C */
8035     {
8036 	if (restart_edit == 0
8037 #ifdef FEAT_CMDWIN
8038 		&& cmdwin_type == 0
8039 #endif
8040 #ifdef FEAT_VISUAL
8041 		&& !VIsual_active
8042 #endif
8043 		&& no_reason)
8044 	    MSG(_("Type  :quit<Enter>  to exit Vim"));
8045 
8046 	/* Don't reset "restart_edit" when 'insertmode' is set, it won't be
8047 	 * set again below when halfway a mapping. */
8048 	if (!p_im)
8049 	    restart_edit = 0;
8050 #ifdef FEAT_CMDWIN
8051 	if (cmdwin_type != 0)
8052 	{
8053 	    cmdwin_result = K_IGNORE;
8054 	    got_int = FALSE;	/* don't stop executing autocommands et al. */
8055 	    return;
8056 	}
8057 #endif
8058     }
8059 
8060 #ifdef FEAT_VISUAL
8061     if (VIsual_active)
8062     {
8063 	end_visual_mode();	/* stop Visual */
8064 	check_cursor_col();	/* make sure cursor is not beyond EOL */
8065 	curwin->w_set_curswant = TRUE;
8066 	redraw_curbuf_later(INVERTED);
8067     }
8068     else
8069 #endif
8070 	if (no_reason)
8071 	    vim_beep();
8072     clearop(cap->oap);
8073 
8074     /* A CTRL-C is often used at the start of a menu.  When 'insertmode' is
8075      * set return to Insert mode afterwards. */
8076     if (restart_edit == 0 && goto_im()
8077 #ifdef FEAT_EX_EXTRA
8078 	    && ex_normal_busy == 0
8079 #endif
8080 	    )
8081 	restart_edit = 'a';
8082 }
8083 
8084 /*
8085  * Handle "A", "a", "I", "i" and <Insert> commands.
8086  */
8087     static void
8088 nv_edit(cap)
8089     cmdarg_T *cap;
8090 {
8091     /* <Insert> is equal to "i" */
8092     if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS)
8093 	cap->cmdchar = 'i';
8094 
8095 #ifdef FEAT_VISUAL
8096     /* in Visual mode "A" and "I" are an operator */
8097     if (VIsual_active && (cap->cmdchar == 'A' || cap->cmdchar == 'I'))
8098 	v_visop(cap);
8099 
8100     /* in Visual mode and after an operator "a" and "i" are for text objects */
8101     else
8102 #endif
8103 	if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
8104 	    && (cap->oap->op_type != OP_NOP
8105 #ifdef FEAT_VISUAL
8106 		|| VIsual_active
8107 #endif
8108 		))
8109     {
8110 #ifdef FEAT_TEXTOBJ
8111 	nv_object(cap);
8112 #else
8113 	clearopbeep(cap->oap);
8114 #endif
8115     }
8116     else if (!curbuf->b_p_ma && !p_im)
8117     {
8118 	/* Only give this error when 'insertmode' is off. */
8119 	EMSG(_(e_modifiable));
8120 	clearop(cap->oap);
8121     }
8122     else if (!checkclearopq(cap->oap))
8123     {
8124 	switch (cap->cmdchar)
8125 	{
8126 	    case 'A':	/* "A"ppend after the line */
8127 		curwin->w_set_curswant = TRUE;
8128 #ifdef FEAT_VIRTUALEDIT
8129 		if (ve_flags == VE_ALL)
8130 		{
8131 		    int save_State = State;
8132 
8133 		    /* Pretent Insert mode here to allow the cursor on the
8134 		     * character past the end of the line */
8135 		    State = INSERT;
8136 		    coladvance((colnr_T)MAXCOL);
8137 		    State = save_State;
8138 		}
8139 		else
8140 #endif
8141 		    curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
8142 		break;
8143 
8144 	    case 'I':	/* "I"nsert before the first non-blank */
8145 		beginline(BL_WHITE);
8146 		break;
8147 
8148 	    case 'a':	/* "a"ppend is like "i"nsert on the next character. */
8149 #ifdef FEAT_VIRTUALEDIT
8150 		/* increment coladd when in virtual space, increment the
8151 		 * column otherwise, also to append after an unprintable char */
8152 		if (virtual_active()
8153 			&& (curwin->w_cursor.coladd > 0
8154 			    || *ml_get_cursor() == NUL
8155 			    || *ml_get_cursor() == TAB))
8156 		    curwin->w_cursor.coladd++;
8157 		else
8158 #endif
8159 		if (*ml_get_cursor() != NUL)
8160 		    inc_cursor();
8161 		break;
8162 	}
8163 
8164 #ifdef FEAT_VIRTUALEDIT
8165 	if (curwin->w_cursor.coladd && cap->cmdchar != 'A')
8166 	{
8167 	    int save_State = State;
8168 
8169 	    /* Pretent Insert mode here to allow the cursor on the
8170 	     * character past the end of the line */
8171 	    State = INSERT;
8172 	    coladvance(getviscol());
8173 	    State = save_State;
8174 	}
8175 #endif
8176 
8177 	invoke_edit(cap, FALSE, cap->cmdchar, FALSE);
8178     }
8179 }
8180 
8181 /*
8182  * Invoke edit() and take care of "restart_edit" and the return value.
8183  */
8184     static void
8185 invoke_edit(cap, repl, cmd, startln)
8186     cmdarg_T	*cap;
8187     int		repl;		/* "r" or "gr" command */
8188     int		cmd;
8189     int		startln;
8190 {
8191     int		restart_edit_save = 0;
8192 
8193     /* Complicated: When the user types "a<C-O>a" we don't want to do Insert
8194      * mode recursively.  But when doing "a<C-O>." or "a<C-O>rx" we do allow
8195      * it. */
8196     if (repl || !stuff_empty())
8197 	restart_edit_save = restart_edit;
8198     else
8199 	restart_edit_save = 0;
8200 
8201     /* Always reset "restart_edit", this is not a restarted edit. */
8202     restart_edit = 0;
8203 
8204     if (edit(cmd, startln, cap->count1))
8205 	cap->retval |= CA_COMMAND_BUSY;
8206 
8207     if (restart_edit == 0)
8208 	restart_edit = restart_edit_save;
8209 }
8210 
8211 #ifdef FEAT_TEXTOBJ
8212 /*
8213  * "a" or "i" while an operator is pending or in Visual mode: object motion.
8214  */
8215     static void
8216 nv_object(cap)
8217     cmdarg_T	*cap;
8218 {
8219     int		flag;
8220     int		include;
8221     char_u	*mps_save;
8222 
8223     if (cap->cmdchar == 'i')
8224 	include = FALSE;    /* "ix" = inner object: exclude white space */
8225     else
8226 	include = TRUE;	    /* "ax" = an object: include white space */
8227 
8228     /* Make sure (), [], {} and <> are in 'matchpairs' */
8229     mps_save = curbuf->b_p_mps;
8230     curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
8231 
8232     switch (cap->nchar)
8233     {
8234 	case 'w': /* "aw" = a word */
8235 		flag = current_word(cap->oap, cap->count1, include, FALSE);
8236 		break;
8237 	case 'W': /* "aW" = a WORD */
8238 		flag = current_word(cap->oap, cap->count1, include, TRUE);
8239 		break;
8240 	case 'b': /* "ab" = a braces block */
8241 	case '(':
8242 	case ')':
8243 		flag = current_block(cap->oap, cap->count1, include, '(', ')');
8244 		break;
8245 	case 'B': /* "aB" = a Brackets block */
8246 	case '{':
8247 	case '}':
8248 		flag = current_block(cap->oap, cap->count1, include, '{', '}');
8249 		break;
8250 	case '[': /* "a[" = a [] block */
8251 	case ']':
8252 		flag = current_block(cap->oap, cap->count1, include, '[', ']');
8253 		break;
8254 	case '<': /* "a<" = a <> block */
8255 	case '>':
8256 		flag = current_block(cap->oap, cap->count1, include, '<', '>');
8257 		break;
8258 	case 'p': /* "ap" = a paragraph */
8259 		flag = current_par(cap->oap, cap->count1, include, 'p');
8260 		break;
8261 	case 's': /* "as" = a sentence */
8262 		flag = current_sent(cap->oap, cap->count1, include);
8263 		break;
8264 	case '"': /* "a"" = a double quoted string */
8265 	case '\'': /* "a'" = a single quoted string */
8266 	case '`': /* "a`" = a backtick quoted string */
8267 		flag = current_quote(cap->oap, cap->count1, include,
8268 								  cap->nchar);
8269 		break;
8270 #if 0	/* TODO */
8271 	case 'S': /* "aS" = a section */
8272 	case 'f': /* "af" = a filename */
8273 	case 'u': /* "au" = a URL */
8274 #endif
8275 	default:
8276 		flag = FAIL;
8277 		break;
8278     }
8279 
8280     curbuf->b_p_mps = mps_save;
8281     if (flag == FAIL)
8282 	clearopbeep(cap->oap);
8283     adjust_cursor_col();
8284     curwin->w_set_curswant = TRUE;
8285 }
8286 #endif
8287 
8288 /*
8289  * "q" command: Start/stop recording.
8290  * "q:", "q/", "q?": edit command-line in command-line window.
8291  */
8292     static void
8293 nv_record(cap)
8294     cmdarg_T	*cap;
8295 {
8296     if (cap->oap->op_type == OP_FORMAT)
8297     {
8298 	/* "gqq" is the same as "gqgq": format line */
8299 	cap->cmdchar = 'g';
8300 	cap->nchar = 'q';
8301 	nv_operator(cap);
8302     }
8303     else if (!checkclearop(cap->oap))
8304     {
8305 #ifdef FEAT_CMDWIN
8306 	if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?')
8307 	{
8308 	    stuffcharReadbuff(cap->nchar);
8309 	    stuffcharReadbuff(K_CMDWIN);
8310 	}
8311 	else
8312 #endif
8313 	    /* (stop) recording into a named register, unless executing a
8314 	     * register */
8315 	    if (!Exec_reg && do_record(cap->nchar) == FAIL)
8316 		clearopbeep(cap->oap);
8317     }
8318 }
8319 
8320 /*
8321  * Handle the "@r" command.
8322  */
8323     static void
8324 nv_at(cap)
8325     cmdarg_T	*cap;
8326 {
8327     if (checkclearop(cap->oap))
8328 	return;
8329 #ifdef FEAT_EVAL
8330     if (cap->nchar == '=')
8331     {
8332 	if (get_expr_register() == NUL)
8333 	    return;
8334     }
8335 #endif
8336     while (cap->count1-- && !got_int)
8337     {
8338 	if (do_execreg(cap->nchar, FALSE, FALSE) == FAIL)
8339 	{
8340 	    clearopbeep(cap->oap);
8341 	    break;
8342 	}
8343 	line_breakcheck();
8344     }
8345 }
8346 
8347 /*
8348  * Handle the CTRL-U and CTRL-D commands.
8349  */
8350     static void
8351 nv_halfpage(cap)
8352     cmdarg_T	*cap;
8353 {
8354     if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1)
8355 	    || (cap->cmdchar == Ctrl_D
8356 		&& curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count))
8357 	clearopbeep(cap->oap);
8358     else if (!checkclearop(cap->oap))
8359 	halfpage(cap->cmdchar == Ctrl_D, cap->count0);
8360 }
8361 
8362 /*
8363  * Handle "J" or "gJ" command.
8364  */
8365     static void
8366 nv_join(cap)
8367     cmdarg_T *cap;
8368 {
8369 #ifdef FEAT_VISUAL
8370     if (VIsual_active)	/* join the visual lines */
8371 	nv_operator(cap);
8372     else
8373 #endif
8374 	if (!checkclearop(cap->oap))
8375     {
8376 	if (cap->count0 <= 1)
8377 	    cap->count0 = 2;	    /* default for join is two lines! */
8378 	if (curwin->w_cursor.lnum + cap->count0 - 1 >
8379 						   curbuf->b_ml.ml_line_count)
8380 	    clearopbeep(cap->oap);  /* beyond last line */
8381 	else
8382 	{
8383 	    prep_redo(cap->oap->regname, cap->count0,
8384 			 NUL, cap->cmdchar, NUL, NUL, cap->nchar);
8385 	    do_do_join(cap->count0, cap->nchar == NUL);
8386 	}
8387     }
8388 }
8389 
8390 /*
8391  * "P", "gP", "p" and "gp" commands.
8392  */
8393     static void
8394 nv_put(cap)
8395     cmdarg_T  *cap;
8396 {
8397 #ifdef FEAT_VISUAL
8398     int		regname = 0;
8399     void	*reg1 = NULL, *reg2 = NULL;
8400 #endif
8401     int		dir;
8402     int		flags = 0;
8403 
8404     if (cap->oap->op_type != OP_NOP)
8405     {
8406 #ifdef FEAT_DIFF
8407 	/* "dp" is ":diffput" */
8408 	if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'p')
8409 	{
8410 	    clearop(cap->oap);
8411 	    nv_diffgetput(TRUE);
8412 	}
8413 	else
8414 #endif
8415 	clearopbeep(cap->oap);
8416     }
8417     else
8418     {
8419 	dir = (cap->cmdchar == 'P'
8420 		|| (cap->cmdchar == 'g' && cap->nchar == 'P'))
8421 							 ? BACKWARD : FORWARD;
8422 	prep_redo_cmd(cap);
8423 	if (cap->cmdchar == 'g')
8424 	    flags |= PUT_CURSEND;
8425 
8426 #ifdef FEAT_VISUAL
8427 	if (VIsual_active)
8428 	{
8429 	    /* Putting in Visual mode: The put text replaces the selected
8430 	     * text.  First delete the selected text, then put the new text.
8431 	     * Need to save and restore the registers that the delete
8432 	     * overwrites if the old contents is being put.
8433 	     */
8434 	    regname = cap->oap->regname;
8435 # ifdef FEAT_CLIPBOARD
8436 	    adjust_clip_reg(&regname);
8437 # endif
8438 	    if (regname == 0 || VIM_ISDIGIT(regname)
8439 # ifdef FEAT_CLIPBOARD
8440 		    || (clip_unnamed && (regname == '*' || regname == '+'))
8441 # endif
8442 
8443 		    )
8444 	    {
8445 		/* the delete is going to overwrite the register we want to
8446 		 * put, save it first. */
8447 		reg1 = get_register(regname, TRUE);
8448 	    }
8449 
8450 	    /* Now delete the selected text. */
8451 	    cap->cmdchar = 'd';
8452 	    cap->nchar = NUL;
8453 	    cap->oap->regname = NUL;
8454 	    nv_operator(cap);
8455 	    do_pending_operator(cap, 0, FALSE);
8456 
8457 	    /* delete PUT_LINE_BACKWARD; */
8458 	    cap->oap->regname = regname;
8459 
8460 	    if (reg1 != NULL)
8461 	    {
8462 		/* Delete probably changed the register we want to put, save
8463 		 * it first. Then put back what was there before the delete. */
8464 		reg2 = get_register(regname, FALSE);
8465 		put_register(regname, reg1);
8466 	    }
8467 
8468 	    /* When deleted a linewise Visual area, put the register as
8469 	     * lines to avoid it joined with the next line.  When deletion was
8470 	     * characterwise, split a line when putting lines. */
8471 	    if (VIsual_mode == 'V')
8472 		flags |= PUT_LINE;
8473 	    else if (VIsual_mode == 'v')
8474 		flags |= PUT_LINE_SPLIT;
8475 	    if (VIsual_mode == Ctrl_V && dir == FORWARD)
8476 		flags |= PUT_LINE_FORWARD;
8477 	    dir = BACKWARD;
8478 	    if ((VIsual_mode != 'V'
8479 			&& curwin->w_cursor.col < curbuf->b_op_start.col)
8480 		    || (VIsual_mode == 'V'
8481 			&& curwin->w_cursor.lnum < curbuf->b_op_start.lnum))
8482 		/* cursor is at the end of the line or end of file, put
8483 		 * forward. */
8484 		dir = FORWARD;
8485 	}
8486 #endif
8487 	do_put(cap->oap->regname, dir, cap->count1, flags);
8488 
8489 #ifdef FEAT_VISUAL
8490 	/* If a register was saved, put it back now. */
8491 	if (reg2 != NULL)
8492 	    put_register(regname, reg2);
8493 #endif
8494 	auto_format(FALSE, TRUE);
8495     }
8496 }
8497 
8498 /*
8499  * "o" and "O" commands.
8500  */
8501     static void
8502 nv_open(cap)
8503     cmdarg_T	*cap;
8504 {
8505 #ifdef FEAT_DIFF
8506     /* "do" is ":diffget" */
8507     if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'o')
8508     {
8509 	clearop(cap->oap);
8510 	nv_diffgetput(FALSE);
8511     }
8512     else
8513 #endif
8514 #ifdef FEAT_VISUAL
8515     if (VIsual_active)  /* switch start and end of visual */
8516 	v_swap_corners(cap->cmdchar);
8517     else
8518 #endif
8519 	n_opencmd(cap);
8520 }
8521 
8522 #ifdef FEAT_SNIFF
8523 /*ARGSUSED*/
8524     static void
8525 nv_sniff(cap)
8526     cmdarg_T	*cap;
8527 {
8528     ProcessSniffRequests();
8529 }
8530 #endif
8531 
8532 #ifdef FEAT_NETBEANS_INTG
8533     static void
8534 nv_nbcmd(cap)
8535     cmdarg_T	*cap;
8536 {
8537     netbeans_keycommand(cap->nchar);
8538 }
8539 #endif
8540 
8541 #ifdef FEAT_DND
8542 /*ARGSUSED*/
8543     static void
8544 nv_drop(cap)
8545     cmdarg_T	*cap;
8546 {
8547     do_put('~', BACKWARD, 1L, PUT_CURSEND);
8548 }
8549 #endif
8550