diff options
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r-- | src/nvim/getchar.c | 153 |
1 files changed, 149 insertions, 4 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 2b2889d4d6..a3af7dc372 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -15,7 +15,10 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/eval.h" +#include "nvim/eval/typval.h" #include "nvim/event/loop.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" @@ -40,7 +43,6 @@ #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/plines.h" -#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/ui.h" @@ -1336,7 +1338,7 @@ static void closescript(void) file_free(scriptin[curscript], false); scriptin[curscript] = NULL; if (curscript > 0) { - --curscript; + curscript--; } } @@ -1695,6 +1697,149 @@ int char_avail(void) return retval != NUL; } +/// "getchar()" and "getcharstr()" functions +static void getchar_common(typval_T *argvars, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + varnumber_T n; + bool error = false; + + no_mapping++; + allow_keys++; + for (;;) { + // Position the cursor. Needed after a message that ends in a space, + // or if event processing caused a redraw. + ui_cursor_goto(msg_row, msg_col); + + if (argvars[0].v_type == VAR_UNKNOWN) { + // getchar(): blocking wait. + // TODO(bfredl): deduplicate shared logic with state_enter ? + if (!char_avail()) { + // flush output before waiting + ui_flush(); + (void)os_inchar(NULL, 0, -1, 0, main_loop.events); + if (!multiqueue_empty(main_loop.events)) { + state_handle_k_event(); + continue; + } + } + n = safe_vgetc(); + } else if (tv_get_number_chk(&argvars[0], &error) == 1) { + // getchar(1): only check if char avail + n = vpeekc_any(); + } else if (error || vpeekc_any() == NUL) { + // illegal argument or getchar(0) and no char avail: return zero + n = 0; + } else { + // getchar(0) and char avail() != NUL: get a character. + // Note that vpeekc_any() returns K_SPECIAL for K_IGNORE. + n = safe_vgetc(); + } + + if (n == K_IGNORE + || n == K_MOUSEMOVE + || n == K_VER_SCROLLBAR + || n == K_HOR_SCROLLBAR) { + continue; + } + break; + } + no_mapping--; + allow_keys--; + + if (!ui_has_messages()) { + // redraw the screen after getchar() + update_screen(CLEAR); + } + + set_vim_var_nr(VV_MOUSE_WIN, 0); + set_vim_var_nr(VV_MOUSE_WINID, 0); + set_vim_var_nr(VV_MOUSE_LNUM, 0); + set_vim_var_nr(VV_MOUSE_COL, 0); + + rettv->vval.v_number = n; + if (n != 0 && (IS_SPECIAL(n) || mod_mask != 0)) { + char_u temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 + int i = 0; + + // Turn a special key into three bytes, plus modifier. + if (mod_mask != 0) { + temp[i++] = K_SPECIAL; + temp[i++] = KS_MODIFIER; + temp[i++] = (char_u)mod_mask; + } + if (IS_SPECIAL(n)) { + temp[i++] = K_SPECIAL; + temp[i++] = (char_u)K_SECOND(n); + temp[i++] = K_THIRD(n); + } else { + i += utf_char2bytes((int)n, (char *)temp + i); + } + assert(i < 10); + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = (char *)vim_strsave(temp); + + if (is_mouse_key((int)n)) { + int row = mouse_row; + int col = mouse_col; + int grid = mouse_grid; + linenr_T lnum; + win_T *wp; + int winnr = 1; + + if (row >= 0 && col >= 0) { + // Find the window at the mouse coordinates and compute the + // text position. + win_T *const win = mouse_find_win(&grid, &row, &col); + if (win == NULL) { + return; + } + (void)mouse_comp_pos(win, &row, &col, &lnum); + for (wp = firstwin; wp != win; wp = wp->w_next) { + winnr++; + } + set_vim_var_nr(VV_MOUSE_WIN, winnr); + set_vim_var_nr(VV_MOUSE_WINID, wp->handle); + set_vim_var_nr(VV_MOUSE_LNUM, lnum); + set_vim_var_nr(VV_MOUSE_COL, col + 1); + } + } + } +} + +/// "getchar()" function +void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); +} + +/// "getcharstr()" function +void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); + + if (rettv->v_type == VAR_NUMBER) { + char temp[7]; // mbyte-char: 6, NUL: 1 + const varnumber_T n = rettv->vval.v_number; + int i = 0; + + if (n != 0) { + i += utf_char2bytes((int)n, (char *)temp); + } + assert(i < 7); + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = xstrdup(temp); + } +} + +/// "getcharmod()" function +void f_getcharmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + rettv->vval.v_number = mod_mask; +} + typedef enum { map_result_fail, // failed, break loop map_result_get, // get a character from typeahead @@ -2251,7 +2396,7 @@ static int vgetorpeek(bool advance) return NUL; } - ++vgetc_busy; + vgetc_busy++; if (advance) { KeyStuffed = FALSE; @@ -2638,7 +2783,7 @@ static int vgetorpeek(bool advance) gotchars(nop_buf, 3); } - --vgetc_busy; + vgetc_busy--; return c; } |