mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	input: Remove CURSORHOLD key
Refactor input.c, normal.c and edit.c to use the K_EVENT special key to trigger the CURSORHOLD event. In normal and edit mode, K_EVENT is treated as K_CURSORHOLD, which enables better handling of arbitrary actions in those states(eg: In normal mode the previous operator counts will be restored). Also fix a test in vim_spec.lua. The test had a wrong assumption: cmdheight is only used to determine when the press enter screen will be shown, not to limit how many lines or control pagination.
This commit is contained in:
		@@ -626,14 +626,9 @@ edit (
 | 
			
		||||
    } while (c == K_IGNORE);
 | 
			
		||||
    input_disable_events();
 | 
			
		||||
 | 
			
		||||
    if (c == K_EVENT) {
 | 
			
		||||
      c = lastc;
 | 
			
		||||
      queue_process_events(loop.events);
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
 | 
			
		||||
    did_cursorhold = TRUE;
 | 
			
		||||
    // Don't want K_EVENT with cursorhold for the second key, e.g., after
 | 
			
		||||
    // CTRL-V.
 | 
			
		||||
    did_cursorhold = true;
 | 
			
		||||
 | 
			
		||||
    if (p_hkmap && KeyTyped)
 | 
			
		||||
      c = hkmap(c);                     /* Hebrew mode mapping */
 | 
			
		||||
@@ -974,9 +969,8 @@ doESCkey:
 | 
			
		||||
    case K_IGNORE:      /* Something mapped to nothing */
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case K_CURSORHOLD:          /* Didn't type something for a while. */
 | 
			
		||||
      apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf);
 | 
			
		||||
      did_cursorhold = TRUE;
 | 
			
		||||
    case K_EVENT:       // some event
 | 
			
		||||
      queue_process_events(loop.events);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case K_HOME:        /* <Home> */
 | 
			
		||||
@@ -1223,9 +1217,10 @@ normalchar:
 | 
			
		||||
      break;
 | 
			
		||||
    }       /* end of switch (c) */
 | 
			
		||||
 | 
			
		||||
    /* If typed something may trigger CursorHoldI again. */
 | 
			
		||||
    if (c != K_CURSORHOLD)
 | 
			
		||||
      did_cursorhold = FALSE;
 | 
			
		||||
    // If typed something may trigger CursorHoldI again.
 | 
			
		||||
    if (c != K_EVENT) {
 | 
			
		||||
      did_cursorhold = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* If the cursor was moved we didn't just insert a space */
 | 
			
		||||
    if (arrow_used)
 | 
			
		||||
 
 | 
			
		||||
@@ -283,7 +283,6 @@ static struct key_name_entry {
 | 
			
		||||
  {K_ZERO,            (char_u *)"Nul"},
 | 
			
		||||
  {K_SNR,             (char_u *)"SNR"},
 | 
			
		||||
  {K_PLUG,            (char_u *)"Plug"},
 | 
			
		||||
  {K_CURSORHOLD,      (char_u *)"CursorHold"},
 | 
			
		||||
  {K_PASTE,           (char_u *)"Paste"},
 | 
			
		||||
  {0,                 NULL}
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -242,7 +242,6 @@ enum key_extra {
 | 
			
		||||
  , KE_X2RELEASE
 | 
			
		||||
 | 
			
		||||
  , KE_DROP             /* DnD data is available */
 | 
			
		||||
  , KE_CURSORHOLD       /* CursorHold event */
 | 
			
		||||
  , KE_NOP              /* doesn't do something */
 | 
			
		||||
  , KE_FOCUSGAINED      /* focus gained */
 | 
			
		||||
  , KE_FOCUSLOST        /* focus lost */
 | 
			
		||||
@@ -437,7 +436,6 @@ enum key_extra {
 | 
			
		||||
#define K_FOCUSGAINED   TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
 | 
			
		||||
#define K_FOCUSLOST     TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
 | 
			
		||||
 | 
			
		||||
#define K_CURSORHOLD    TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
 | 
			
		||||
#define K_EVENT         TERMCAP2KEY(KS_EXTRA, KE_EVENT)
 | 
			
		||||
#define K_PASTE         TERMCAP2KEY(KS_EXTRA, KE_PASTE)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -336,7 +336,7 @@ static const struct nv_cmd {
 | 
			
		||||
  {K_SELECT,  nv_select,      0,                      0},
 | 
			
		||||
  {K_F8,      farsi_fkey,     0,                      0},
 | 
			
		||||
  {K_F9,      farsi_fkey,     0,                      0},
 | 
			
		||||
  {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG,           0},
 | 
			
		||||
  {K_EVENT,   nv_event,       NV_KEEPREG,             0},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Number of commands in nv_cmds[]. */
 | 
			
		||||
@@ -492,8 +492,8 @@ static void normal_prepare(NormalState *s)
 | 
			
		||||
    s->set_prevcount = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Restore counts from before receiving K_CURSORHOLD.  This means after
 | 
			
		||||
  // typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not
 | 
			
		||||
  // Restore counts from before receiving K_EVENT.  This means after
 | 
			
		||||
  // typing "3", handling K_EVENT and then typing "2" we get "32", not
 | 
			
		||||
  // "3 * 2".
 | 
			
		||||
  if (s->oa.prev_opcount > 0 || s->oa.prev_count0 > 0) {
 | 
			
		||||
    s->ca.opcount = s->oa.prev_opcount;
 | 
			
		||||
@@ -616,9 +616,9 @@ getcount:
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (c == K_CURSORHOLD) {
 | 
			
		||||
  if (c == K_EVENT) {
 | 
			
		||||
    // Save the count values so that ca.opcount and ca.count0 are exactly
 | 
			
		||||
    // the same when coming back here after handling K_CURSORHOLD.
 | 
			
		||||
    // the same when coming back here after handling K_EVENT.
 | 
			
		||||
    s->oa.prev_opcount = s->ca.opcount;
 | 
			
		||||
    s->oa.prev_count0 = s->ca.count0;
 | 
			
		||||
  } else if (s->ca.opcount != 0)  {
 | 
			
		||||
@@ -891,7 +891,7 @@ getcount:
 | 
			
		||||
  if (need_flushbuf) {
 | 
			
		||||
    ui_flush();
 | 
			
		||||
  }
 | 
			
		||||
  if (s->ca.cmdchar != K_IGNORE) {
 | 
			
		||||
  if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) {
 | 
			
		||||
    did_cursorhold = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -1022,7 +1022,7 @@ normal_end:
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (s->oa.op_type == OP_NOP && s->oa.regname == 0
 | 
			
		||||
      && s->ca.cmdchar != K_CURSORHOLD) {
 | 
			
		||||
      && s->ca.cmdchar != K_EVENT) {
 | 
			
		||||
    clear_showcmd();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -3147,7 +3147,7 @@ bool add_to_showcmd(int c)
 | 
			
		||||
    K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
 | 
			
		||||
    K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT,
 | 
			
		||||
    K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
 | 
			
		||||
    K_CURSORHOLD,
 | 
			
		||||
    K_EVENT,
 | 
			
		||||
    0
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -7567,16 +7567,11 @@ static void nv_open(cmdarg_T *cap)
 | 
			
		||||
    n_opencmd(cap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Trigger CursorHold event.
 | 
			
		||||
 * When waiting for a character for 'updatetime' K_CURSORHOLD is put in the
 | 
			
		||||
 * input buffer.  "did_cursorhold" is set to avoid retriggering.
 | 
			
		||||
 */
 | 
			
		||||
static void nv_cursorhold(cmdarg_T *cap)
 | 
			
		||||
// Handle an arbitrary event in normal mode
 | 
			
		||||
static void nv_event(cmdarg_T *cap)
 | 
			
		||||
{
 | 
			
		||||
  apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, false, curbuf);
 | 
			
		||||
  did_cursorhold = true;
 | 
			
		||||
  cap->retval |= CA_COMMAND_BUSY;       /* don't call edit() now */
 | 
			
		||||
  queue_process_events(loop.events);
 | 
			
		||||
  cap->retval |= CA_COMMAND_BUSY;       // don't call edit() now
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -7594,18 +7589,9 @@ void normal_cmd(oparg_T *oap, bool toplevel)
 | 
			
		||||
  s.toplevel = toplevel;
 | 
			
		||||
  s.oa = *oap;
 | 
			
		||||
  normal_prepare(&s);
 | 
			
		||||
 | 
			
		||||
  input_enable_events();
 | 
			
		||||
  int c = safe_vgetc();
 | 
			
		||||
  input_disable_events();
 | 
			
		||||
 | 
			
		||||
  if (c == K_EVENT) {
 | 
			
		||||
    queue_process_events(loop.events);
 | 
			
		||||
    goto end;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  (void)normal_execute(&s, c);
 | 
			
		||||
 | 
			
		||||
end:
 | 
			
		||||
  *oap = s.oa;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,8 +36,8 @@ typedef struct oparg_S {
 | 
			
		||||
  bool block_mode;              /* current operator is Visual block mode */
 | 
			
		||||
  colnr_T start_vcol;           /* start col for block mode operator */
 | 
			
		||||
  colnr_T end_vcol;             /* end col for block mode operator */
 | 
			
		||||
  long prev_opcount;            /* ca.opcount saved for K_CURSORHOLD */
 | 
			
		||||
  long prev_count0;             /* ca.count0 saved for K_CURSORHOLD */
 | 
			
		||||
  long prev_opcount;            // ca.opcount saved for K_EVENT
 | 
			
		||||
  long prev_count0;             // ca.count0 saved for K_EVENT
 | 
			
		||||
} oparg_T;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,21 @@ void input_stop(void)
 | 
			
		||||
  stream_close(&read_stream, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cursorhold_event(void **argv)
 | 
			
		||||
{
 | 
			
		||||
  event_T event = State & INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
 | 
			
		||||
  apply_autocmds(event, NULL, NULL, false, curbuf);
 | 
			
		||||
  did_cursorhold = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void create_cursorhold_event(void)
 | 
			
		||||
{
 | 
			
		||||
  // If the queue had any items, this function should not have been
 | 
			
		||||
  // called(inbuf_poll would return kInputAvail)
 | 
			
		||||
  assert(queue_empty(loop.events));
 | 
			
		||||
  queue_put(loop.events, cursorhold_event, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Low level input function
 | 
			
		||||
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
 | 
			
		||||
{
 | 
			
		||||
@@ -87,16 +102,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    if ((result = inbuf_poll((int)p_ut)) == kInputNone) {
 | 
			
		||||
      if (trigger_cursorhold() && maxlen >= 3
 | 
			
		||||
          && !typebuf_changed(tb_change_cnt)) {
 | 
			
		||||
        buf[0] = K_SPECIAL;
 | 
			
		||||
        buf[1] = KS_EXTRA;
 | 
			
		||||
        buf[2] = KE_CURSORHOLD;
 | 
			
		||||
        return 3;
 | 
			
		||||
      if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
 | 
			
		||||
        create_cursorhold_event();
 | 
			
		||||
      } else {
 | 
			
		||||
        before_blocking();
 | 
			
		||||
        result = inbuf_poll(-1);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      before_blocking();
 | 
			
		||||
      result = inbuf_poll(-1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -247,33 +247,21 @@ describe('vim_* functions', function()
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        {1:very fail}                               |
 | 
			
		||||
      ]])
 | 
			
		||||
      helpers.wait()
 | 
			
		||||
 | 
			
		||||
      -- shows up to &cmdheight lines
 | 
			
		||||
      nvim_async('err_write', 'more fail\n')
 | 
			
		||||
      nvim_async('err_write', 'too fail\n')
 | 
			
		||||
      nvim_async('err_write', 'more fail\ntoo fail\n')
 | 
			
		||||
      screen:expect([[
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        {1:very fail}                               |
 | 
			
		||||
        {1:more fail}                               |
 | 
			
		||||
        {2:Press ENTER or type command to continue}^ |
 | 
			
		||||
      ]])
 | 
			
		||||
 | 
			
		||||
      -- shows the rest after return
 | 
			
		||||
      feed('<cr>')
 | 
			
		||||
      screen:expect([[
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        ~                                       |
 | 
			
		||||
        {1:very fail}                               |
 | 
			
		||||
        {1:more fail}                               |
 | 
			
		||||
        {2:Press ENTER or type command to continue} |
 | 
			
		||||
        {1:too fail}                                |
 | 
			
		||||
        {2:Press ENTER or type command to continue}^ |
 | 
			
		||||
      ]])
 | 
			
		||||
      feed('<cr>')  -- exit the press ENTER screen
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user