comparison src/normal.c @ 18135:1868ec23360e v8.1.2062

patch 8.1.2062: the mouse code is spread out Commit: https://github.com/vim/vim/commit/b20b9e14ddd8db111e886ad0494e15b955159426 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 21 20:48:04 2019 +0200 patch 8.1.2062: the mouse code is spread out Problem: The mouse code is spread out. Solution: Move all the mouse code to mouse.c. (Yegappan Lakshmanan, closes #4959)
author Bram Moolenaar <Bram@vim.org>
date Sat, 21 Sep 2019 21:00:07 +0200
parents aeabc666a119
children 5e10ee16f4b4
comparison
equal deleted inserted replaced
18134:c06a2bc8144f 18135:1868ec23360e
28 static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount); 28 static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount);
29 #endif 29 #endif
30 static int nv_compare(const void *s1, const void *s2); 30 static int nv_compare(const void *s1, const void *s2);
31 static void op_colon(oparg_T *oap); 31 static void op_colon(oparg_T *oap);
32 static void op_function(oparg_T *oap); 32 static void op_function(oparg_T *oap);
33 #if defined(FEAT_MOUSE)
34 static void find_start_of_word(pos_T *);
35 static void find_end_of_word(pos_T *);
36 static int get_mouse_class(char_u *p);
37 #endif
38 static void prep_redo(int regname, long, int, int, int, int, int);
39 static void clearop(oparg_T *oap);
40 static void clearopbeep(oparg_T *oap);
41 static void unshift_special(cmdarg_T *cap); 33 static void unshift_special(cmdarg_T *cap);
42 static void may_clear_cmdline(void); 34 static void may_clear_cmdline(void);
43 #ifdef FEAT_CMDL_INFO 35 #ifdef FEAT_CMDL_INFO
44 static void del_from_showcmd(int); 36 static void del_from_showcmd(int);
45 #endif 37 #endif
53 static void nv_nop(cmdarg_T *cap); 45 static void nv_nop(cmdarg_T *cap);
54 static void nv_error(cmdarg_T *cap); 46 static void nv_error(cmdarg_T *cap);
55 static void nv_help(cmdarg_T *cap); 47 static void nv_help(cmdarg_T *cap);
56 static void nv_addsub(cmdarg_T *cap); 48 static void nv_addsub(cmdarg_T *cap);
57 static void nv_page(cmdarg_T *cap); 49 static void nv_page(cmdarg_T *cap);
58 #ifdef FEAT_MOUSE
59 static void nv_mousescroll(cmdarg_T *cap);
60 static void nv_mouse(cmdarg_T *cap);
61 #endif
62 static void nv_scroll_line(cmdarg_T *cap);
63 static void nv_zet(cmdarg_T *cap); 50 static void nv_zet(cmdarg_T *cap);
64 #ifdef FEAT_GUI 51 #ifdef FEAT_GUI
65 static void nv_ver_scrollbar(cmdarg_T *cap); 52 static void nv_ver_scrollbar(cmdarg_T *cap);
66 static void nv_hor_scrollbar(cmdarg_T *cap); 53 static void nv_hor_scrollbar(cmdarg_T *cap);
67 #endif 54 #endif
2199 #else 2186 #else
2200 emsg(_("E775: Eval feature not available")); 2187 emsg(_("E775: Eval feature not available"));
2201 #endif 2188 #endif
2202 } 2189 }
2203 2190
2204 #if defined(FEAT_MOUSE) || defined(PROTO)
2205 /*
2206 * Do the appropriate action for the current mouse click in the current mode.
2207 * Not used for Command-line mode.
2208 *
2209 * Normal and Visual Mode:
2210 * event modi- position visual change action
2211 * fier cursor window
2212 * left press - yes end yes
2213 * left press C yes end yes "^]" (2)
2214 * left press S yes end (popup: extend) yes "*" (2)
2215 * left drag - yes start if moved no
2216 * left relse - yes start if moved no
2217 * middle press - yes if not active no put register
2218 * middle press - yes if active no yank and put
2219 * right press - yes start or extend yes
2220 * right press S yes no change yes "#" (2)
2221 * right drag - yes extend no
2222 * right relse - yes extend no
2223 *
2224 * Insert or Replace Mode:
2225 * event modi- position visual change action
2226 * fier cursor window
2227 * left press - yes (cannot be active) yes
2228 * left press C yes (cannot be active) yes "CTRL-O^]" (2)
2229 * left press S yes (cannot be active) yes "CTRL-O*" (2)
2230 * left drag - yes start or extend (1) no CTRL-O (1)
2231 * left relse - yes start or extend (1) no CTRL-O (1)
2232 * middle press - no (cannot be active) no put register
2233 * right press - yes start or extend yes CTRL-O
2234 * right press S yes (cannot be active) yes "CTRL-O#" (2)
2235 *
2236 * (1) only if mouse pointer moved since press
2237 * (2) only if click is in same buffer
2238 *
2239 * Return TRUE if start_arrow() should be called for edit mode.
2240 */
2241 int
2242 do_mouse(
2243 oparg_T *oap, /* operator argument, can be NULL */
2244 int c, /* K_LEFTMOUSE, etc */
2245 int dir, /* Direction to 'put' if necessary */
2246 long count,
2247 int fixindent) /* PUT_FIXINDENT if fixing indent necessary */
2248 {
2249 static int do_always = FALSE; /* ignore 'mouse' setting next time */
2250 static int got_click = FALSE; /* got a click some time back */
2251
2252 int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
2253 int is_click; /* If FALSE it's a drag or release event */
2254 int is_drag; /* If TRUE it's a drag event */
2255 int jump_flags = 0; /* flags for jump_to_mouse() */
2256 pos_T start_visual;
2257 int moved; /* Has cursor moved? */
2258 int in_status_line; /* mouse in status line */
2259 static int in_tab_line = FALSE; /* mouse clicked in tab line */
2260 int in_sep_line; /* mouse in vertical separator line */
2261 int c1, c2;
2262 #if defined(FEAT_FOLDING)
2263 pos_T save_cursor;
2264 #endif
2265 win_T *old_curwin = curwin;
2266 static pos_T orig_cursor;
2267 colnr_T leftcol, rightcol;
2268 pos_T end_visual;
2269 int diff;
2270 int old_active = VIsual_active;
2271 int old_mode = VIsual_mode;
2272 int regname;
2273
2274 #if defined(FEAT_FOLDING)
2275 save_cursor = curwin->w_cursor;
2276 #endif
2277
2278 /*
2279 * When GUI is active, always recognize mouse events, otherwise:
2280 * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
2281 * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
2282 * - For command line and insert mode 'mouse' is checked before calling
2283 * do_mouse().
2284 */
2285 if (do_always)
2286 do_always = FALSE;
2287 else
2288 #ifdef FEAT_GUI
2289 if (!gui.in_use)
2290 #endif
2291 {
2292 if (VIsual_active)
2293 {
2294 if (!mouse_has(MOUSE_VISUAL))
2295 return FALSE;
2296 }
2297 else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
2298 return FALSE;
2299 }
2300
2301 for (;;)
2302 {
2303 which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
2304 if (is_drag)
2305 {
2306 /* If the next character is the same mouse event then use that
2307 * one. Speeds up dragging the status line. */
2308 if (vpeekc() != NUL)
2309 {
2310 int nc;
2311 int save_mouse_row = mouse_row;
2312 int save_mouse_col = mouse_col;
2313
2314 /* Need to get the character, peeking doesn't get the actual
2315 * one. */
2316 nc = safe_vgetc();
2317 if (c == nc)
2318 continue;
2319 vungetc(nc);
2320 mouse_row = save_mouse_row;
2321 mouse_col = save_mouse_col;
2322 }
2323 }
2324 break;
2325 }
2326
2327 if (c == K_MOUSEMOVE)
2328 {
2329 // Mouse moved without a button pressed.
2330 #ifdef FEAT_BEVAL_TERM
2331 ui_may_remove_balloon();
2332 if (p_bevalterm)
2333 {
2334 profile_setlimit(p_bdlay, &bevalexpr_due);
2335 bevalexpr_due_set = TRUE;
2336 }
2337 #endif
2338 #ifdef FEAT_TEXT_PROP
2339 popup_handle_mouse_moved();
2340 #endif
2341 return FALSE;
2342 }
2343
2344 #ifdef FEAT_MOUSESHAPE
2345 /* May have stopped dragging the status or separator line. The pointer is
2346 * most likely still on the status or separator line. */
2347 if (!is_drag && drag_status_line)
2348 {
2349 drag_status_line = FALSE;
2350 update_mouseshape(SHAPE_IDX_STATUS);
2351 }
2352 if (!is_drag && drag_sep_line)
2353 {
2354 drag_sep_line = FALSE;
2355 update_mouseshape(SHAPE_IDX_VSEP);
2356 }
2357 #endif
2358
2359 /*
2360 * Ignore drag and release events if we didn't get a click.
2361 */
2362 if (is_click)
2363 got_click = TRUE;
2364 else
2365 {
2366 if (!got_click) /* didn't get click, ignore */
2367 return FALSE;
2368 if (!is_drag) /* release, reset got_click */
2369 {
2370 got_click = FALSE;
2371 if (in_tab_line)
2372 {
2373 in_tab_line = FALSE;
2374 return FALSE;
2375 }
2376 }
2377 }
2378
2379 /*
2380 * CTRL right mouse button does CTRL-T
2381 */
2382 if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
2383 {
2384 if (State & INSERT)
2385 stuffcharReadbuff(Ctrl_O);
2386 if (count > 1)
2387 stuffnumReadbuff(count);
2388 stuffcharReadbuff(Ctrl_T);
2389 got_click = FALSE; /* ignore drag&release now */
2390 return FALSE;
2391 }
2392
2393 /*
2394 * CTRL only works with left mouse button
2395 */
2396 if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
2397 return FALSE;
2398
2399 /*
2400 * When a modifier is down, ignore drag and release events, as well as
2401 * multiple clicks and the middle mouse button.
2402 * Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
2403 */
2404 if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT
2405 | MOD_MASK_META))
2406 && (!is_click
2407 || (mod_mask & MOD_MASK_MULTI_CLICK)
2408 || which_button == MOUSE_MIDDLE)
2409 && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))
2410 && mouse_model_popup()
2411 && which_button == MOUSE_LEFT)
2412 && !((mod_mask & MOD_MASK_ALT)
2413 && !mouse_model_popup()
2414 && which_button == MOUSE_RIGHT)
2415 )
2416 return FALSE;
2417
2418 /*
2419 * If the button press was used as the movement command for an operator
2420 * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
2421 * drag/release events.
2422 */
2423 if (!is_click && which_button == MOUSE_MIDDLE)
2424 return FALSE;
2425
2426 if (oap != NULL)
2427 regname = oap->regname;
2428 else
2429 regname = 0;
2430
2431 /*
2432 * Middle mouse button does a 'put' of the selected text
2433 */
2434 if (which_button == MOUSE_MIDDLE)
2435 {
2436 if (State == NORMAL)
2437 {
2438 /*
2439 * If an operator was pending, we don't know what the user wanted
2440 * to do. Go back to normal mode: Clear the operator and beep().
2441 */
2442 if (oap != NULL && oap->op_type != OP_NOP)
2443 {
2444 clearopbeep(oap);
2445 return FALSE;
2446 }
2447
2448 /*
2449 * If visual was active, yank the highlighted text and put it
2450 * before the mouse pointer position.
2451 * In Select mode replace the highlighted text with the clipboard.
2452 */
2453 if (VIsual_active)
2454 {
2455 if (VIsual_select)
2456 {
2457 stuffcharReadbuff(Ctrl_G);
2458 stuffReadbuff((char_u *)"\"+p");
2459 }
2460 else
2461 {
2462 stuffcharReadbuff('y');
2463 stuffcharReadbuff(K_MIDDLEMOUSE);
2464 }
2465 do_always = TRUE; /* ignore 'mouse' setting next time */
2466 return FALSE;
2467 }
2468 /*
2469 * The rest is below jump_to_mouse()
2470 */
2471 }
2472
2473 else if ((State & INSERT) == 0)
2474 return FALSE;
2475
2476 /*
2477 * Middle click in insert mode doesn't move the mouse, just insert the
2478 * contents of a register. '.' register is special, can't insert that
2479 * with do_put().
2480 * Also paste at the cursor if the current mode isn't in 'mouse' (only
2481 * happens for the GUI).
2482 */
2483 if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
2484 {
2485 if (regname == '.')
2486 insert_reg(regname, TRUE);
2487 else
2488 {
2489 #ifdef FEAT_CLIPBOARD
2490 if (clip_star.available && regname == 0)
2491 regname = '*';
2492 #endif
2493 if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
2494 insert_reg(regname, TRUE);
2495 else
2496 {
2497 do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
2498
2499 /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
2500 AppendCharToRedobuff(Ctrl_R);
2501 AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
2502 AppendCharToRedobuff(regname == 0 ? '"' : regname);
2503 }
2504 }
2505 return FALSE;
2506 }
2507 }
2508
2509 /* When dragging or button-up stay in the same window. */
2510 if (!is_click)
2511 jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
2512
2513 start_visual.lnum = 0;
2514
2515 /* Check for clicking in the tab page line. */
2516 if (mouse_row == 0 && firstwin->w_winrow > 0)
2517 {
2518 if (is_drag)
2519 {
2520 if (in_tab_line)
2521 {
2522 c1 = TabPageIdxs[mouse_col];
2523 tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
2524 ? c1 - 1 : c1);
2525 }
2526 return FALSE;
2527 }
2528
2529 /* click in a tab selects that tab page */
2530 if (is_click
2531 # ifdef FEAT_CMDWIN
2532 && cmdwin_type == 0
2533 # endif
2534 && mouse_col < Columns)
2535 {
2536 in_tab_line = TRUE;
2537 c1 = TabPageIdxs[mouse_col];
2538 if (c1 >= 0)
2539 {
2540 if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
2541 {
2542 /* double click opens new page */
2543 end_visual_mode();
2544 tabpage_new();
2545 tabpage_move(c1 == 0 ? 9999 : c1 - 1);
2546 }
2547 else
2548 {
2549 /* Go to specified tab page, or next one if not clicking
2550 * on a label. */
2551 goto_tabpage(c1);
2552
2553 /* It's like clicking on the status line of a window. */
2554 if (curwin != old_curwin)
2555 end_visual_mode();
2556 }
2557 }
2558 else
2559 {
2560 tabpage_T *tp;
2561
2562 /* Close the current or specified tab page. */
2563 if (c1 == -999)
2564 tp = curtab;
2565 else
2566 tp = find_tabpage(-c1);
2567 if (tp == curtab)
2568 {
2569 if (first_tabpage->tp_next != NULL)
2570 tabpage_close(FALSE);
2571 }
2572 else if (tp != NULL)
2573 tabpage_close_other(tp, FALSE);
2574 }
2575 }
2576 return TRUE;
2577 }
2578 else if (is_drag && in_tab_line)
2579 {
2580 c1 = TabPageIdxs[mouse_col];
2581 tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
2582 return FALSE;
2583 }
2584
2585 /*
2586 * When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
2587 * right button up -> pop-up menu
2588 * shift-left button -> right button
2589 * alt-left button -> alt-right button
2590 */
2591 if (mouse_model_popup())
2592 {
2593 if (which_button == MOUSE_RIGHT
2594 && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
2595 {
2596 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
2597 || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
2598 || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON) \
2599 || defined(FEAT_TERM_POPUP_MENU)
2600 # ifdef FEAT_GUI
2601 if (gui.in_use)
2602 {
2603 # if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
2604 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2605 if (!is_click)
2606 /* Ignore right button release events, only shows the popup
2607 * menu on the button down event. */
2608 return FALSE;
2609 # endif
2610 # if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
2611 if (is_click || is_drag)
2612 /* Ignore right button down and drag mouse events. Windows
2613 * only shows the popup menu on the button up event. */
2614 return FALSE;
2615 # endif
2616 }
2617 # endif
2618 # if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
2619 else
2620 # endif
2621 # if defined(FEAT_TERM_POPUP_MENU)
2622 if (!is_click)
2623 /* Ignore right button release events, only shows the popup
2624 * menu on the button down event. */
2625 return FALSE;
2626 #endif
2627
2628 jump_flags = 0;
2629 if (STRCMP(p_mousem, "popup_setpos") == 0)
2630 {
2631 /* First set the cursor position before showing the popup
2632 * menu. */
2633 if (VIsual_active)
2634 {
2635 pos_T m_pos;
2636
2637 /*
2638 * set MOUSE_MAY_STOP_VIS if we are outside the
2639 * selection or the current window (might have false
2640 * negative here)
2641 */
2642 if (mouse_row < curwin->w_winrow
2643 || mouse_row
2644 > (curwin->w_winrow + curwin->w_height))
2645 jump_flags = MOUSE_MAY_STOP_VIS;
2646 else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
2647 jump_flags = MOUSE_MAY_STOP_VIS;
2648 else
2649 {
2650 if ((LT_POS(curwin->w_cursor, VIsual)
2651 && (LT_POS(m_pos, curwin->w_cursor)
2652 || LT_POS(VIsual, m_pos)))
2653 || (LT_POS(VIsual, curwin->w_cursor)
2654 && (LT_POS(m_pos, VIsual)
2655 || LT_POS(curwin->w_cursor, m_pos))))
2656 {
2657 jump_flags = MOUSE_MAY_STOP_VIS;
2658 }
2659 else if (VIsual_mode == Ctrl_V)
2660 {
2661 getvcols(curwin, &curwin->w_cursor, &VIsual,
2662 &leftcol, &rightcol);
2663 getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
2664 if (m_pos.col < leftcol || m_pos.col > rightcol)
2665 jump_flags = MOUSE_MAY_STOP_VIS;
2666 }
2667 }
2668 }
2669 else
2670 jump_flags = MOUSE_MAY_STOP_VIS;
2671 }
2672 if (jump_flags)
2673 {
2674 jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
2675 update_curbuf(VIsual_active ? INVERTED : VALID);
2676 setcursor();
2677 out_flush(); /* Update before showing popup menu */
2678 }
2679 # ifdef FEAT_MENU
2680 show_popupmenu();
2681 got_click = FALSE; /* ignore release events */
2682 # endif
2683 return (jump_flags & CURSOR_MOVED) != 0;
2684 #else
2685 return FALSE;
2686 #endif
2687 }
2688 if (which_button == MOUSE_LEFT
2689 && (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)))
2690 {
2691 which_button = MOUSE_RIGHT;
2692 mod_mask &= ~MOD_MASK_SHIFT;
2693 }
2694 }
2695
2696 if ((State & (NORMAL | INSERT))
2697 && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
2698 {
2699 if (which_button == MOUSE_LEFT)
2700 {
2701 if (is_click)
2702 {
2703 /* stop Visual mode for a left click in a window, but not when
2704 * on a status line */
2705 if (VIsual_active)
2706 jump_flags |= MOUSE_MAY_STOP_VIS;
2707 }
2708 else if (mouse_has(MOUSE_VISUAL))
2709 jump_flags |= MOUSE_MAY_VIS;
2710 }
2711 else if (which_button == MOUSE_RIGHT)
2712 {
2713 if (is_click && VIsual_active)
2714 {
2715 /*
2716 * Remember the start and end of visual before moving the
2717 * cursor.
2718 */
2719 if (LT_POS(curwin->w_cursor, VIsual))
2720 {
2721 start_visual = curwin->w_cursor;
2722 end_visual = VIsual;
2723 }
2724 else
2725 {
2726 start_visual = VIsual;
2727 end_visual = curwin->w_cursor;
2728 }
2729 }
2730 jump_flags |= MOUSE_FOCUS;
2731 if (mouse_has(MOUSE_VISUAL))
2732 jump_flags |= MOUSE_MAY_VIS;
2733 }
2734 }
2735
2736 /*
2737 * If an operator is pending, ignore all drags and releases until the
2738 * next mouse click.
2739 */
2740 if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
2741 {
2742 got_click = FALSE;
2743 oap->motion_type = MCHAR;
2744 }
2745
2746 /* When releasing the button let jump_to_mouse() know. */
2747 if (!is_click && !is_drag)
2748 jump_flags |= MOUSE_RELEASED;
2749
2750 /*
2751 * JUMP!
2752 */
2753 jump_flags = jump_to_mouse(jump_flags,
2754 oap == NULL ? NULL : &(oap->inclusive), which_button);
2755
2756 #ifdef FEAT_MENU
2757 /* A click in the window toolbar has no side effects. */
2758 if (jump_flags & MOUSE_WINBAR)
2759 return FALSE;
2760 #endif
2761 moved = (jump_flags & CURSOR_MOVED);
2762 in_status_line = (jump_flags & IN_STATUS_LINE);
2763 in_sep_line = (jump_flags & IN_SEP_LINE);
2764
2765 #ifdef FEAT_NETBEANS_INTG
2766 if (isNetbeansBuffer(curbuf)
2767 && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
2768 {
2769 int key = KEY2TERMCAP1(c);
2770
2771 if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
2772 || key == (int)KE_RIGHTRELEASE)
2773 netbeans_button_release(which_button);
2774 }
2775 #endif
2776
2777 /* When jumping to another window, clear a pending operator. That's a bit
2778 * friendlier than beeping and not jumping to that window. */
2779 if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
2780 clearop(oap);
2781
2782 #ifdef FEAT_FOLDING
2783 if (mod_mask == 0
2784 && !is_drag
2785 && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
2786 && which_button == MOUSE_LEFT)
2787 {
2788 /* open or close a fold at this line */
2789 if (jump_flags & MOUSE_FOLD_OPEN)
2790 openFold(curwin->w_cursor.lnum, 1L);
2791 else
2792 closeFold(curwin->w_cursor.lnum, 1L);
2793 /* don't move the cursor if still in the same window */
2794 if (curwin == old_curwin)
2795 curwin->w_cursor = save_cursor;
2796 }
2797 #endif
2798
2799 #if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
2800 if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
2801 {
2802 clip_modeless(which_button, is_click, is_drag);
2803 return FALSE;
2804 }
2805 #endif
2806
2807 /* Set global flag that we are extending the Visual area with mouse
2808 * dragging; temporarily minimize 'scrolloff'. */
2809 if (VIsual_active && is_drag && get_scrolloff_value())
2810 {
2811 /* In the very first line, allow scrolling one line */
2812 if (mouse_row == 0)
2813 mouse_dragging = 2;
2814 else
2815 mouse_dragging = 1;
2816 }
2817
2818 /* When dragging the mouse above the window, scroll down. */
2819 if (is_drag && mouse_row < 0 && !in_status_line)
2820 {
2821 scroll_redraw(FALSE, 1L);
2822 mouse_row = 0;
2823 }
2824
2825 if (start_visual.lnum) /* right click in visual mode */
2826 {
2827 /* When ALT is pressed make Visual mode blockwise. */
2828 if (mod_mask & MOD_MASK_ALT)
2829 VIsual_mode = Ctrl_V;
2830
2831 /*
2832 * In Visual-block mode, divide the area in four, pick up the corner
2833 * that is in the quarter that the cursor is in.
2834 */
2835 if (VIsual_mode == Ctrl_V)
2836 {
2837 getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
2838 if (curwin->w_curswant > (leftcol + rightcol) / 2)
2839 end_visual.col = leftcol;
2840 else
2841 end_visual.col = rightcol;
2842 if (curwin->w_cursor.lnum >=
2843 (start_visual.lnum + end_visual.lnum) / 2)
2844 end_visual.lnum = start_visual.lnum;
2845
2846 /* move VIsual to the right column */
2847 start_visual = curwin->w_cursor; /* save the cursor pos */
2848 curwin->w_cursor = end_visual;
2849 coladvance(end_visual.col);
2850 VIsual = curwin->w_cursor;
2851 curwin->w_cursor = start_visual; /* restore the cursor */
2852 }
2853 else
2854 {
2855 /*
2856 * If the click is before the start of visual, change the start.
2857 * If the click is after the end of visual, change the end. If
2858 * the click is inside the visual, change the closest side.
2859 */
2860 if (LT_POS(curwin->w_cursor, start_visual))
2861 VIsual = end_visual;
2862 else if (LT_POS(end_visual, curwin->w_cursor))
2863 VIsual = start_visual;
2864 else
2865 {
2866 /* In the same line, compare column number */
2867 if (end_visual.lnum == start_visual.lnum)
2868 {
2869 if (curwin->w_cursor.col - start_visual.col >
2870 end_visual.col - curwin->w_cursor.col)
2871 VIsual = start_visual;
2872 else
2873 VIsual = end_visual;
2874 }
2875
2876 /* In different lines, compare line number */
2877 else
2878 {
2879 diff = (curwin->w_cursor.lnum - start_visual.lnum) -
2880 (end_visual.lnum - curwin->w_cursor.lnum);
2881
2882 if (diff > 0) /* closest to end */
2883 VIsual = start_visual;
2884 else if (diff < 0) /* closest to start */
2885 VIsual = end_visual;
2886 else /* in the middle line */
2887 {
2888 if (curwin->w_cursor.col <
2889 (start_visual.col + end_visual.col) / 2)
2890 VIsual = end_visual;
2891 else
2892 VIsual = start_visual;
2893 }
2894 }
2895 }
2896 }
2897 }
2898 /*
2899 * If Visual mode started in insert mode, execute "CTRL-O"
2900 */
2901 else if ((State & INSERT) && VIsual_active)
2902 stuffcharReadbuff(Ctrl_O);
2903
2904 /*
2905 * Middle mouse click: Put text before cursor.
2906 */
2907 if (which_button == MOUSE_MIDDLE)
2908 {
2909 #ifdef FEAT_CLIPBOARD
2910 if (clip_star.available && regname == 0)
2911 regname = '*';
2912 #endif
2913 if (yank_register_mline(regname))
2914 {
2915 if (mouse_past_bottom)
2916 dir = FORWARD;
2917 }
2918 else if (mouse_past_eol)
2919 dir = FORWARD;
2920
2921 if (fixindent)
2922 {
2923 c1 = (dir == BACKWARD) ? '[' : ']';
2924 c2 = 'p';
2925 }
2926 else
2927 {
2928 c1 = (dir == FORWARD) ? 'p' : 'P';
2929 c2 = NUL;
2930 }
2931 prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
2932
2933 /*
2934 * Remember where the paste started, so in edit() Insstart can be set
2935 * to this position
2936 */
2937 if (restart_edit != 0)
2938 where_paste_started = curwin->w_cursor;
2939 do_put(regname, dir, count, fixindent | PUT_CURSEND);
2940 }
2941
2942 #if defined(FEAT_QUICKFIX)
2943 /*
2944 * Ctrl-Mouse click or double click in a quickfix window jumps to the
2945 * error under the mouse pointer.
2946 */
2947 else if (((mod_mask & MOD_MASK_CTRL)
2948 || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
2949 && bt_quickfix(curbuf))
2950 {
2951 if (curwin->w_llist_ref == NULL) /* quickfix window */
2952 do_cmdline_cmd((char_u *)".cc");
2953 else /* location list window */
2954 do_cmdline_cmd((char_u *)".ll");
2955 got_click = FALSE; /* ignore drag&release now */
2956 }
2957 #endif
2958
2959 /*
2960 * Ctrl-Mouse click (or double click in a help window) jumps to the tag
2961 * under the mouse pointer.
2962 */
2963 else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
2964 && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
2965 {
2966 if (State & INSERT)
2967 stuffcharReadbuff(Ctrl_O);
2968 stuffcharReadbuff(Ctrl_RSB);
2969 got_click = FALSE; /* ignore drag&release now */
2970 }
2971
2972 /*
2973 * Shift-Mouse click searches for the next occurrence of the word under
2974 * the mouse pointer
2975 */
2976 else if ((mod_mask & MOD_MASK_SHIFT))
2977 {
2978 if ((State & INSERT) || (VIsual_active && VIsual_select))
2979 stuffcharReadbuff(Ctrl_O);
2980 if (which_button == MOUSE_LEFT)
2981 stuffcharReadbuff('*');
2982 else /* MOUSE_RIGHT */
2983 stuffcharReadbuff('#');
2984 }
2985
2986 /* Handle double clicks, unless on status line */
2987 else if (in_status_line)
2988 {
2989 #ifdef FEAT_MOUSESHAPE
2990 if ((is_drag || is_click) && !drag_status_line)
2991 {
2992 drag_status_line = TRUE;
2993 update_mouseshape(-1);
2994 }
2995 #endif
2996 }
2997 else if (in_sep_line)
2998 {
2999 #ifdef FEAT_MOUSESHAPE
3000 if ((is_drag || is_click) && !drag_sep_line)
3001 {
3002 drag_sep_line = TRUE;
3003 update_mouseshape(-1);
3004 }
3005 #endif
3006 }
3007 else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
3008 && mouse_has(MOUSE_VISUAL))
3009 {
3010 if (is_click || !VIsual_active)
3011 {
3012 if (VIsual_active)
3013 orig_cursor = VIsual;
3014 else
3015 {
3016 check_visual_highlight();
3017 VIsual = curwin->w_cursor;
3018 orig_cursor = VIsual;
3019 VIsual_active = TRUE;
3020 VIsual_reselect = TRUE;
3021 /* start Select mode if 'selectmode' contains "mouse" */
3022 may_start_select('o');
3023 setmouse();
3024 }
3025 if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
3026 {
3027 /* Double click with ALT pressed makes it blockwise. */
3028 if (mod_mask & MOD_MASK_ALT)
3029 VIsual_mode = Ctrl_V;
3030 else
3031 VIsual_mode = 'v';
3032 }
3033 else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
3034 VIsual_mode = 'V';
3035 else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
3036 VIsual_mode = Ctrl_V;
3037 #ifdef FEAT_CLIPBOARD
3038 /* Make sure the clipboard gets updated. Needed because start and
3039 * end may still be the same, and the selection needs to be owned */
3040 clip_star.vmode = NUL;
3041 #endif
3042 }
3043 /*
3044 * A double click selects a word or a block.
3045 */
3046 if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
3047 {
3048 pos_T *pos = NULL;
3049 int gc;
3050
3051 if (is_click)
3052 {
3053 /* If the character under the cursor (skipping white space) is
3054 * not a word character, try finding a match and select a (),
3055 * {}, [], #if/#endif, etc. block. */
3056 end_visual = curwin->w_cursor;
3057 while (gc = gchar_pos(&end_visual), VIM_ISWHITE(gc))
3058 inc(&end_visual);
3059 if (oap != NULL)
3060 oap->motion_type = MCHAR;
3061 if (oap != NULL
3062 && VIsual_mode == 'v'
3063 && !vim_iswordc(gchar_pos(&end_visual))
3064 && EQUAL_POS(curwin->w_cursor, VIsual)
3065 && (pos = findmatch(oap, NUL)) != NULL)
3066 {
3067 curwin->w_cursor = *pos;
3068 if (oap->motion_type == MLINE)
3069 VIsual_mode = 'V';
3070 else if (*p_sel == 'e')
3071 {
3072 if (LT_POS(curwin->w_cursor, VIsual))
3073 ++VIsual.col;
3074 else
3075 ++curwin->w_cursor.col;
3076 }
3077 }
3078 }
3079
3080 if (pos == NULL && (is_click || is_drag))
3081 {
3082 /* When not found a match or when dragging: extend to include
3083 * a word. */
3084 if (LT_POS(curwin->w_cursor, orig_cursor))
3085 {
3086 find_start_of_word(&curwin->w_cursor);
3087 find_end_of_word(&VIsual);
3088 }
3089 else
3090 {
3091 find_start_of_word(&VIsual);
3092 if (*p_sel == 'e' && *ml_get_cursor() != NUL)
3093 curwin->w_cursor.col +=
3094 (*mb_ptr2len)(ml_get_cursor());
3095 find_end_of_word(&curwin->w_cursor);
3096 }
3097 }
3098 curwin->w_set_curswant = TRUE;
3099 }
3100 if (is_click)
3101 redraw_curbuf_later(INVERTED); /* update the inversion */
3102 }
3103 else if (VIsual_active && !old_active)
3104 {
3105 if (mod_mask & MOD_MASK_ALT)
3106 VIsual_mode = Ctrl_V;
3107 else
3108 VIsual_mode = 'v';
3109 }
3110
3111 /* If Visual mode changed show it later. */
3112 if ((!VIsual_active && old_active && mode_displayed)
3113 || (VIsual_active && p_smd && msg_silent == 0
3114 && (!old_active || VIsual_mode != old_mode)))
3115 redraw_cmdline = TRUE;
3116
3117 return moved;
3118 }
3119
3120 /*
3121 * Move "pos" back to the start of the word it's in.
3122 */
3123 static void
3124 find_start_of_word(pos_T *pos)
3125 {
3126 char_u *line;
3127 int cclass;
3128 int col;
3129
3130 line = ml_get(pos->lnum);
3131 cclass = get_mouse_class(line + pos->col);
3132
3133 while (pos->col > 0)
3134 {
3135 col = pos->col - 1;
3136 col -= (*mb_head_off)(line, line + col);
3137 if (get_mouse_class(line + col) != cclass)
3138 break;
3139 pos->col = col;
3140 }
3141 }
3142
3143 /*
3144 * Move "pos" forward to the end of the word it's in.
3145 * When 'selection' is "exclusive", the position is just after the word.
3146 */
3147 static void
3148 find_end_of_word(pos_T *pos)
3149 {
3150 char_u *line;
3151 int cclass;
3152 int col;
3153
3154 line = ml_get(pos->lnum);
3155 if (*p_sel == 'e' && pos->col > 0)
3156 {
3157 --pos->col;
3158 pos->col -= (*mb_head_off)(line, line + pos->col);
3159 }
3160 cclass = get_mouse_class(line + pos->col);
3161 while (line[pos->col] != NUL)
3162 {
3163 col = pos->col + (*mb_ptr2len)(line + pos->col);
3164 if (get_mouse_class(line + col) != cclass)
3165 {
3166 if (*p_sel == 'e')
3167 pos->col = col;
3168 break;
3169 }
3170 pos->col = col;
3171 }
3172 }
3173
3174 /*
3175 * Get class of a character for selection: same class means same word.
3176 * 0: blank
3177 * 1: punctuation groups
3178 * 2: normal word character
3179 * >2: multi-byte word character.
3180 */
3181 static int
3182 get_mouse_class(char_u *p)
3183 {
3184 int c;
3185
3186 if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
3187 return mb_get_class(p);
3188
3189 c = *p;
3190 if (c == ' ' || c == '\t')
3191 return 0;
3192
3193 if (vim_iswordc(c))
3194 return 2;
3195
3196 /*
3197 * There are a few special cases where we want certain combinations of
3198 * characters to be considered as a single word. These are things like
3199 * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc. Otherwise, each
3200 * character is in its own class.
3201 */
3202 if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
3203 return 1;
3204 return c;
3205 }
3206 #endif /* FEAT_MOUSE */
3207
3208 /* 2191 /*
3209 * Check if highlighting for visual mode is possible, give a warning message 2192 * Check if highlighting for visual mode is possible, give a warning message
3210 * if not. 2193 * if not.
3211 */ 2194 */
3212 void 2195 void
3529 2512
3530 /* 2513 /*
3531 * Prepare for redo of any command. 2514 * Prepare for redo of any command.
3532 * Note that only the last argument can be a multi-byte char. 2515 * Note that only the last argument can be a multi-byte char.
3533 */ 2516 */
3534 static void 2517 void
3535 prep_redo( 2518 prep_redo(
3536 int regname, 2519 int regname,
3537 long num, 2520 long num,
3538 int cmd1, 2521 int cmd1,
3539 int cmd2, 2522 int cmd2,
3588 return FALSE; 2571 return FALSE;
3589 clearopbeep(oap); 2572 clearopbeep(oap);
3590 return TRUE; 2573 return TRUE;
3591 } 2574 }
3592 2575
3593 static void 2576 void
3594 clearop(oparg_T *oap) 2577 clearop(oparg_T *oap)
3595 { 2578 {
3596 oap->op_type = OP_NOP; 2579 oap->op_type = OP_NOP;
3597 oap->regname = 0; 2580 oap->regname = 0;
3598 oap->motion_force = NUL; 2581 oap->motion_force = NUL;
3599 oap->use_reg_one = FALSE; 2582 oap->use_reg_one = FALSE;
3600 } 2583 }
3601 2584
3602 static void 2585 void
3603 clearopbeep(oparg_T *oap) 2586 clearopbeep(oparg_T *oap)
3604 { 2587 {
3605 clearop(oap); 2588 clearop(oap);
3606 beep_flush(); 2589 beep_flush();
3607 } 2590 }
4511 curwin->w_curswant = MAXCOL; /* stick in the last column */ 3494 curwin->w_curswant = MAXCOL; /* stick in the last column */
4512 3495
4513 return retval; 3496 return retval;
4514 } 3497 }
4515 3498
4516 #ifdef FEAT_MOUSE
4517 /*
4518 * Mouse scroll wheel: Default action is to scroll three lines, or one page
4519 * when Shift or Ctrl is used.
4520 * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
4521 * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
4522 */
4523 static void
4524 nv_mousescroll(cmdarg_T *cap)
4525 {
4526 win_T *old_curwin = curwin, *wp;
4527
4528 if (mouse_row >= 0 && mouse_col >= 0)
4529 {
4530 int row, col;
4531
4532 row = mouse_row;
4533 col = mouse_col;
4534
4535 /* find the window at the pointer coordinates */
4536 wp = mouse_find_win(&row, &col, FIND_POPUP);
4537 if (wp == NULL)
4538 return;
4539 #ifdef FEAT_TEXT_PROP
4540 if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
4541 return;
4542 #endif
4543 curwin = wp;
4544 curbuf = curwin->w_buffer;
4545 }
4546
4547 if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
4548 {
4549 # ifdef FEAT_TERMINAL
4550 if (term_use_loop())
4551 /* This window is a terminal window, send the mouse event there.
4552 * Set "typed" to FALSE to avoid an endless loop. */
4553 send_keys_to_term(curbuf->b_term, cap->cmdchar, FALSE);
4554 else
4555 # endif
4556 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
4557 {
4558 (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
4559 }
4560 else
4561 {
4562 // Don't scroll more than half the window height.
4563 if (curwin->w_height < 6)
4564 {
4565 cap->count1 = curwin->w_height / 2;
4566 if (cap->count1 == 0)
4567 cap->count1 = 1;
4568 }
4569 else
4570 cap->count1 = 3;
4571 cap->count0 = cap->count1;
4572 nv_scroll_line(cap);
4573 }
4574 #ifdef FEAT_TEXT_PROP
4575 if (WIN_IS_POPUP(curwin))
4576 popup_set_firstline(curwin);
4577 #endif
4578 }
4579 # ifdef FEAT_GUI
4580 else
4581 {
4582 /* Horizontal scroll - only allowed when 'wrap' is disabled */
4583 if (!curwin->w_p_wrap)
4584 {
4585 int val, step = 6;
4586
4587 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
4588 step = curwin->w_width;
4589 val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
4590 if (val < 0)
4591 val = 0;
4592
4593 gui_do_horiz_scroll(val, TRUE);
4594 }
4595 }
4596 # endif
4597 # ifdef FEAT_SYN_HL
4598 if (curwin != old_curwin && curwin->w_p_cul)
4599 redraw_for_cursorline(curwin);
4600 # endif
4601
4602 curwin->w_redr_status = TRUE;
4603
4604 curwin = old_curwin;
4605 curbuf = curwin->w_buffer;
4606 }
4607
4608 /*
4609 * Mouse clicks and drags.
4610 */
4611 static void
4612 nv_mouse(cmdarg_T *cap)
4613 {
4614 (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
4615 }
4616 #endif
4617
4618 /* 3499 /*
4619 * Handle CTRL-E and CTRL-Y commands: scroll a line up or down. 3500 * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
4620 * cap->arg must be TRUE for CTRL-E. 3501 * cap->arg must be TRUE for CTRL-E.
4621 */ 3502 */
4622 static void 3503 void
4623 nv_scroll_line(cmdarg_T *cap) 3504 nv_scroll_line(cmdarg_T *cap)
4624 { 3505 {
4625 if (!checkclearop(cap->oap)) 3506 if (!checkclearop(cap->oap))
4626 scroll_redraw(cap->arg, cap->count1); 3507 scroll_redraw(cap->arg, cap->count1);
4627 } 3508 }
7570 VIsual_active = TRUE; 6451 VIsual_active = TRUE;
7571 VIsual_reselect = TRUE; 6452 VIsual_reselect = TRUE;
7572 if (!cap->arg) 6453 if (!cap->arg)
7573 /* start Select mode when 'selectmode' contains "cmd" */ 6454 /* start Select mode when 'selectmode' contains "cmd" */
7574 may_start_select('c'); 6455 may_start_select('c');
7575 #ifdef FEAT_MOUSE
7576 setmouse(); 6456 setmouse();
7577 #endif
7578 if (p_smd && msg_silent == 0) 6457 if (p_smd && msg_silent == 0)
7579 redraw_cmdline = TRUE; /* show visual mode later */ 6458 redraw_cmdline = TRUE; /* show visual mode later */
7580 /* 6459 /*
7581 * For V and ^V, we multiply the number of lines even if there 6460 * For V and ^V, we multiply the number of lines even if there
7582 * was only one -- webb 6461 * was only one -- webb
7685 6564
7686 #ifdef FEAT_FOLDING 6565 #ifdef FEAT_FOLDING
7687 foldAdjustVisual(); 6566 foldAdjustVisual();
7688 #endif 6567 #endif
7689 6568
7690 #ifdef FEAT_MOUSE
7691 setmouse(); 6569 setmouse();
7692 #endif
7693 #ifdef FEAT_CONCEAL 6570 #ifdef FEAT_CONCEAL
7694 /* Check for redraw after changing the state. */ 6571 /* Check for redraw after changing the state. */
7695 conceal_check_cursor_line(); 6572 conceal_check_cursor_line();
7696 #endif 6573 #endif
7697 6574
7852 */ 6729 */
7853 if (cap->arg) 6730 if (cap->arg)
7854 VIsual_select = TRUE; 6731 VIsual_select = TRUE;
7855 else 6732 else
7856 may_start_select('c'); 6733 may_start_select('c');
7857 #ifdef FEAT_MOUSE
7858 setmouse(); 6734 setmouse();
7859 #endif
7860 #ifdef FEAT_CLIPBOARD 6735 #ifdef FEAT_CLIPBOARD
7861 /* Make sure the clipboard gets updated. Needed because start and 6736 /* Make sure the clipboard gets updated. Needed because start and
7862 * end are still the same, and the selection needs to be owned */ 6737 * end are still the same, and the selection needs to be owned */
7863 clip_star.vmode = NUL; 6738 clip_star.vmode = NUL;
7864 #endif 6739 #endif