Mercurial > vim
comparison src/terminal.c @ 13448:a62b0bbc8834 v8.0.1598
patch 8.0.1598: cannot select text in a terminal with the mouse
commit https://github.com/vim/vim/commit/c48369c3fc507f398abbc933a60f653c6abe6701
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Mar 11 19:30:45 2018 +0100
patch 8.0.1598: cannot select text in a terminal with the mouse
Problem: Cannot select text in a terminal with the mouse.
Solution: When a job in a terminal is not consuming mouse events, use them
for modeless selection. Also stop Insert mode when clicking in a
terminal window.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 11 Mar 2018 19:45:05 +0100 |
parents | 9f06f7aca74c |
children | 0e7a56b18d61 |
comparison
equal
deleted
inserted
replaced
13447:17eebaa3188f | 13448:a62b0bbc8834 |
---|---|
36 * that buffer, attributes come from the scrollback buffer tl_scrollback. | 36 * that buffer, attributes come from the scrollback buffer tl_scrollback. |
37 * When the buffer is changed it is turned into a normal buffer, the attributes | 37 * When the buffer is changed it is turned into a normal buffer, the attributes |
38 * in tl_scrollback are no longer used. | 38 * in tl_scrollback are no longer used. |
39 * | 39 * |
40 * TODO: | 40 * TODO: |
41 * - if the job in the terminal does not support the mouse, we can use the | |
42 * mouse in the Terminal window for copy/paste and scrolling. | |
43 * - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for | 41 * - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for |
44 * - In the GUI use a terminal emulator for :!cmd. Make the height the same as | 42 * - In the GUI use a terminal emulator for :!cmd. Make the height the same as |
45 * the window and position it higher up when it gets filled, so it looks like | 43 * the window and position it higher up when it gets filled, so it looks like |
46 * the text scrolls up. | 44 * the text scrolls up. |
47 * - implement term_setsize() | 45 * - implement term_setsize() |
895 | 893 |
896 vterm_mouse_move(vterm, mouse_row - W_WINROW(curwin), | 894 vterm_mouse_move(vterm, mouse_row - W_WINROW(curwin), |
897 mouse_col - curwin->w_wincol, mod); | 895 mouse_col - curwin->w_wincol, mod); |
898 if (button != 0) | 896 if (button != 0) |
899 vterm_mouse_button(vterm, button, pressed, mod); | 897 vterm_mouse_button(vterm, button, pressed, mod); |
898 return TRUE; | |
899 } | |
900 | |
901 static int enter_mouse_col = -1; | |
902 static int enter_mouse_row = -1; | |
903 | |
904 /* | |
905 * Handle a mouse click, drag or release. | |
906 * Return TRUE when a mouse event is sent to the terminal. | |
907 */ | |
908 static int | |
909 term_mouse_click(VTerm *vterm, int key) | |
910 { | |
911 #if defined(FEAT_CLIPBOARD) | |
912 /* For modeless selection mouse drag and release events are ignored, unless | |
913 * they are preceded with a mouse down event */ | |
914 static int ignore_drag_release = TRUE; | |
915 VTermMouseState mouse_state; | |
916 | |
917 vterm_state_get_mousestate(vterm_obtain_state(vterm), &mouse_state); | |
918 if (mouse_state.flags == 0) | |
919 { | |
920 /* Terminal is not using the mouse, use modeless selection. */ | |
921 switch (key) | |
922 { | |
923 case K_LEFTDRAG: | |
924 case K_LEFTRELEASE: | |
925 case K_RIGHTDRAG: | |
926 case K_RIGHTRELEASE: | |
927 /* Ignore drag and release events when the button-down wasn't | |
928 * seen before. */ | |
929 if (ignore_drag_release) | |
930 { | |
931 int save_mouse_col, save_mouse_row; | |
932 | |
933 if (enter_mouse_col < 0) | |
934 break; | |
935 | |
936 /* mouse click in the window gave us focus, handle that | |
937 * click now */ | |
938 save_mouse_col = mouse_col; | |
939 save_mouse_row = mouse_row; | |
940 mouse_col = enter_mouse_col; | |
941 mouse_row = enter_mouse_row; | |
942 clip_modeless(MOUSE_LEFT, TRUE, FALSE); | |
943 mouse_col = save_mouse_col; | |
944 mouse_row = save_mouse_row; | |
945 } | |
946 /* FALLTHROUGH */ | |
947 case K_LEFTMOUSE: | |
948 case K_RIGHTMOUSE: | |
949 if (key == K_LEFTRELEASE || key == K_RIGHTRELEASE) | |
950 ignore_drag_release = TRUE; | |
951 else | |
952 ignore_drag_release = FALSE; | |
953 /* Should we call mouse_has() here? */ | |
954 if (clip_star.available) | |
955 { | |
956 int button, is_click, is_drag; | |
957 | |
958 button = get_mouse_button(KEY2TERMCAP1(key), | |
959 &is_click, &is_drag); | |
960 if (mouse_model_popup() && button == MOUSE_LEFT | |
961 && (mod_mask & MOD_MASK_SHIFT)) | |
962 { | |
963 /* Translate shift-left to right button. */ | |
964 button = MOUSE_RIGHT; | |
965 mod_mask &= ~MOD_MASK_SHIFT; | |
966 } | |
967 clip_modeless(button, is_click, is_drag); | |
968 } | |
969 break; | |
970 | |
971 case K_MIDDLEMOUSE: | |
972 if (clip_star.available) | |
973 insert_reg('*', TRUE); | |
974 break; | |
975 } | |
976 enter_mouse_col = -1; | |
977 return FALSE; | |
978 } | |
979 #endif | |
980 enter_mouse_col = -1; | |
981 | |
982 switch (key) | |
983 { | |
984 case K_LEFTMOUSE: | |
985 case K_LEFTMOUSE_NM: term_send_mouse(vterm, 1, 1); break; | |
986 case K_LEFTDRAG: term_send_mouse(vterm, 1, 1); break; | |
987 case K_LEFTRELEASE: | |
988 case K_LEFTRELEASE_NM: term_send_mouse(vterm, 1, 0); break; | |
989 case K_MOUSEMOVE: term_send_mouse(vterm, 0, 0); break; | |
990 case K_MIDDLEMOUSE: term_send_mouse(vterm, 2, 1); break; | |
991 case K_MIDDLEDRAG: term_send_mouse(vterm, 2, 1); break; | |
992 case K_MIDDLERELEASE: term_send_mouse(vterm, 2, 0); break; | |
993 case K_RIGHTMOUSE: term_send_mouse(vterm, 3, 1); break; | |
994 case K_RIGHTDRAG: term_send_mouse(vterm, 3, 1); break; | |
995 case K_RIGHTRELEASE: term_send_mouse(vterm, 3, 0); break; | |
996 } | |
900 return TRUE; | 997 return TRUE; |
901 } | 998 } |
902 | 999 |
903 /* | 1000 /* |
904 * Convert typed key "c" into bytes to send to the job. | 1001 * Convert typed key "c" into bytes to send to the job. |
993 case K_MOUSEDOWN: other = term_send_mouse(vterm, 4, 1); break; | 1090 case K_MOUSEDOWN: other = term_send_mouse(vterm, 4, 1); break; |
994 case K_MOUSELEFT: /* TODO */ return 0; | 1091 case K_MOUSELEFT: /* TODO */ return 0; |
995 case K_MOUSERIGHT: /* TODO */ return 0; | 1092 case K_MOUSERIGHT: /* TODO */ return 0; |
996 | 1093 |
997 case K_LEFTMOUSE: | 1094 case K_LEFTMOUSE: |
998 case K_LEFTMOUSE_NM: other = term_send_mouse(vterm, 1, 1); break; | 1095 case K_LEFTMOUSE_NM: |
999 case K_LEFTDRAG: other = term_send_mouse(vterm, 1, 1); break; | 1096 case K_LEFTDRAG: |
1000 case K_LEFTRELEASE: | 1097 case K_LEFTRELEASE: |
1001 case K_LEFTRELEASE_NM: other = term_send_mouse(vterm, 1, 0); break; | 1098 case K_LEFTRELEASE_NM: |
1002 case K_MOUSEMOVE: other = term_send_mouse(vterm, 0, 0); break; | 1099 case K_MOUSEMOVE: |
1003 case K_MIDDLEMOUSE: other = term_send_mouse(vterm, 2, 1); break; | 1100 case K_MIDDLEMOUSE: |
1004 case K_MIDDLEDRAG: other = term_send_mouse(vterm, 2, 1); break; | 1101 case K_MIDDLEDRAG: |
1005 case K_MIDDLERELEASE: other = term_send_mouse(vterm, 2, 0); break; | 1102 case K_MIDDLERELEASE: |
1006 case K_RIGHTMOUSE: other = term_send_mouse(vterm, 3, 1); break; | 1103 case K_RIGHTMOUSE: |
1007 case K_RIGHTDRAG: other = term_send_mouse(vterm, 3, 1); break; | 1104 case K_RIGHTDRAG: |
1008 case K_RIGHTRELEASE: other = term_send_mouse(vterm, 3, 0); break; | 1105 case K_RIGHTRELEASE: if (!term_mouse_click(vterm, c)) |
1106 return 0; | |
1107 other = TRUE; | |
1108 break; | |
1109 | |
1009 case K_X1MOUSE: /* TODO */ return 0; | 1110 case K_X1MOUSE: /* TODO */ return 0; |
1010 case K_X1DRAG: /* TODO */ return 0; | 1111 case K_X1DRAG: /* TODO */ return 0; |
1011 case K_X1RELEASE: /* TODO */ return 0; | 1112 case K_X1RELEASE: /* TODO */ return 0; |
1012 case K_X2MOUSE: /* TODO */ return 0; | 1113 case K_X2MOUSE: /* TODO */ return 0; |
1013 case K_X2DRAG: /* TODO */ return 0; | 1114 case K_X2DRAG: /* TODO */ return 0; |
1471 got_int = FALSE; | 1572 got_int = FALSE; |
1472 State = save_State; | 1573 State = save_State; |
1473 return c; | 1574 return c; |
1474 } | 1575 } |
1475 | 1576 |
1577 static int mouse_was_outside = FALSE; | |
1578 | |
1476 /* | 1579 /* |
1477 * Send keys to terminal. | 1580 * Send keys to terminal. |
1478 * Return FAIL when the key needs to be handled in Normal mode. | 1581 * Return FAIL when the key needs to be handled in Normal mode. |
1479 * Return OK when the key was dropped or sent to the terminal. | 1582 * Return OK when the key was dropped or sent to the terminal. |
1480 */ | 1583 */ |
1481 int | 1584 int |
1482 send_keys_to_term(term_T *term, int c, int typed) | 1585 send_keys_to_term(term_T *term, int c, int typed) |
1483 { | 1586 { |
1484 char msg[KEY_BUF_LEN]; | 1587 char msg[KEY_BUF_LEN]; |
1485 size_t len; | 1588 size_t len; |
1486 static int mouse_was_outside = FALSE; | |
1487 int dragging_outside = FALSE; | 1589 int dragging_outside = FALSE; |
1488 | 1590 |
1489 /* Catch keys that need to be handled as in Normal mode. */ | 1591 /* Catch keys that need to be handled as in Normal mode. */ |
1490 switch (c) | 1592 switch (c) |
1491 { | 1593 { |
1727 #endif | 1829 #endif |
1728 desired_cursor_color = (char_u *)""; | 1830 desired_cursor_color = (char_u *)""; |
1729 desired_cursor_shape = -1; | 1831 desired_cursor_shape = -1; |
1730 desired_cursor_blink = -1; | 1832 desired_cursor_blink = -1; |
1731 may_output_cursor_props(); | 1833 may_output_cursor_props(); |
1834 } | |
1835 | |
1836 /* | |
1837 * Called when entering a window with the mouse. If this is a terminal window | |
1838 * we may want to change state. | |
1839 */ | |
1840 void | |
1841 term_win_entered() | |
1842 { | |
1843 term_T *term = curbuf->b_term; | |
1844 | |
1845 if (term != NULL) | |
1846 { | |
1847 if (term_use_loop()) | |
1848 { | |
1849 reset_VIsual_and_resel(); | |
1850 if (State & INSERT) | |
1851 stop_insert_mode = TRUE; | |
1852 } | |
1853 mouse_was_outside = FALSE; | |
1854 enter_mouse_col = mouse_col; | |
1855 enter_mouse_row = mouse_row; | |
1856 } | |
1732 } | 1857 } |
1733 | 1858 |
1734 /* | 1859 /* |
1735 * Returns TRUE if the current window contains a terminal and we are sending | 1860 * Returns TRUE if the current window contains a terminal and we are sending |
1736 * keys to the job. | 1861 * keys to the job. |