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);
 | 
					    } while (c == K_IGNORE);
 | 
				
			||||||
    input_disable_events();
 | 
					    input_disable_events();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (c == K_EVENT) {
 | 
					    // Don't want K_EVENT with cursorhold for the second key, e.g., after
 | 
				
			||||||
      c = lastc;
 | 
					    // CTRL-V.
 | 
				
			||||||
      queue_process_events(loop.events);
 | 
					    did_cursorhold = true;
 | 
				
			||||||
      continue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
 | 
					 | 
				
			||||||
    did_cursorhold = TRUE;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (p_hkmap && KeyTyped)
 | 
					    if (p_hkmap && KeyTyped)
 | 
				
			||||||
      c = hkmap(c);                     /* Hebrew mode mapping */
 | 
					      c = hkmap(c);                     /* Hebrew mode mapping */
 | 
				
			||||||
@@ -974,9 +969,8 @@ doESCkey:
 | 
				
			|||||||
    case K_IGNORE:      /* Something mapped to nothing */
 | 
					    case K_IGNORE:      /* Something mapped to nothing */
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case K_CURSORHOLD:          /* Didn't type something for a while. */
 | 
					    case K_EVENT:       // some event
 | 
				
			||||||
      apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf);
 | 
					      queue_process_events(loop.events);
 | 
				
			||||||
      did_cursorhold = TRUE;
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case K_HOME:        /* <Home> */
 | 
					    case K_HOME:        /* <Home> */
 | 
				
			||||||
@@ -1223,9 +1217,10 @@ normalchar:
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }       /* end of switch (c) */
 | 
					    }       /* end of switch (c) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If typed something may trigger CursorHoldI again. */
 | 
					    // If typed something may trigger CursorHoldI again.
 | 
				
			||||||
    if (c != K_CURSORHOLD)
 | 
					    if (c != K_EVENT) {
 | 
				
			||||||
      did_cursorhold = FALSE;
 | 
					      did_cursorhold = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If the cursor was moved we didn't just insert a space */
 | 
					    /* If the cursor was moved we didn't just insert a space */
 | 
				
			||||||
    if (arrow_used)
 | 
					    if (arrow_used)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -283,7 +283,6 @@ static struct key_name_entry {
 | 
				
			|||||||
  {K_ZERO,            (char_u *)"Nul"},
 | 
					  {K_ZERO,            (char_u *)"Nul"},
 | 
				
			||||||
  {K_SNR,             (char_u *)"SNR"},
 | 
					  {K_SNR,             (char_u *)"SNR"},
 | 
				
			||||||
  {K_PLUG,            (char_u *)"Plug"},
 | 
					  {K_PLUG,            (char_u *)"Plug"},
 | 
				
			||||||
  {K_CURSORHOLD,      (char_u *)"CursorHold"},
 | 
					 | 
				
			||||||
  {K_PASTE,           (char_u *)"Paste"},
 | 
					  {K_PASTE,           (char_u *)"Paste"},
 | 
				
			||||||
  {0,                 NULL}
 | 
					  {0,                 NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -242,7 +242,6 @@ enum key_extra {
 | 
				
			|||||||
  , KE_X2RELEASE
 | 
					  , KE_X2RELEASE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  , KE_DROP             /* DnD data is available */
 | 
					  , KE_DROP             /* DnD data is available */
 | 
				
			||||||
  , KE_CURSORHOLD       /* CursorHold event */
 | 
					 | 
				
			||||||
  , KE_NOP              /* doesn't do something */
 | 
					  , KE_NOP              /* doesn't do something */
 | 
				
			||||||
  , KE_FOCUSGAINED      /* focus gained */
 | 
					  , KE_FOCUSGAINED      /* focus gained */
 | 
				
			||||||
  , KE_FOCUSLOST        /* focus lost */
 | 
					  , KE_FOCUSLOST        /* focus lost */
 | 
				
			||||||
@@ -437,7 +436,6 @@ enum key_extra {
 | 
				
			|||||||
#define K_FOCUSGAINED   TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
 | 
					#define K_FOCUSGAINED   TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
 | 
				
			||||||
#define K_FOCUSLOST     TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
 | 
					#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_EVENT         TERMCAP2KEY(KS_EXTRA, KE_EVENT)
 | 
				
			||||||
#define K_PASTE         TERMCAP2KEY(KS_EXTRA, KE_PASTE)
 | 
					#define K_PASTE         TERMCAP2KEY(KS_EXTRA, KE_PASTE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -336,7 +336,7 @@ static const struct nv_cmd {
 | 
				
			|||||||
  {K_SELECT,  nv_select,      0,                      0},
 | 
					  {K_SELECT,  nv_select,      0,                      0},
 | 
				
			||||||
  {K_F8,      farsi_fkey,     0,                      0},
 | 
					  {K_F8,      farsi_fkey,     0,                      0},
 | 
				
			||||||
  {K_F9,      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[]. */
 | 
					/* Number of commands in nv_cmds[]. */
 | 
				
			||||||
@@ -492,8 +492,8 @@ static void normal_prepare(NormalState *s)
 | 
				
			|||||||
    s->set_prevcount = true;
 | 
					    s->set_prevcount = true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Restore counts from before receiving K_CURSORHOLD.  This means after
 | 
					  // Restore counts from before receiving K_EVENT.  This means after
 | 
				
			||||||
  // typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not
 | 
					  // typing "3", handling K_EVENT and then typing "2" we get "32", not
 | 
				
			||||||
  // "3 * 2".
 | 
					  // "3 * 2".
 | 
				
			||||||
  if (s->oa.prev_opcount > 0 || s->oa.prev_count0 > 0) {
 | 
					  if (s->oa.prev_opcount > 0 || s->oa.prev_count0 > 0) {
 | 
				
			||||||
    s->ca.opcount = s->oa.prev_opcount;
 | 
					    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
 | 
					    // 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_opcount = s->ca.opcount;
 | 
				
			||||||
    s->oa.prev_count0 = s->ca.count0;
 | 
					    s->oa.prev_count0 = s->ca.count0;
 | 
				
			||||||
  } else if (s->ca.opcount != 0)  {
 | 
					  } else if (s->ca.opcount != 0)  {
 | 
				
			||||||
@@ -891,7 +891,7 @@ getcount:
 | 
				
			|||||||
  if (need_flushbuf) {
 | 
					  if (need_flushbuf) {
 | 
				
			||||||
    ui_flush();
 | 
					    ui_flush();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (s->ca.cmdchar != K_IGNORE) {
 | 
					  if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) {
 | 
				
			||||||
    did_cursorhold = false;
 | 
					    did_cursorhold = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1022,7 +1022,7 @@ normal_end:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (s->oa.op_type == OP_NOP && s->oa.regname == 0
 | 
					  if (s->oa.op_type == OP_NOP && s->oa.regname == 0
 | 
				
			||||||
      && s->ca.cmdchar != K_CURSORHOLD) {
 | 
					      && s->ca.cmdchar != K_EVENT) {
 | 
				
			||||||
    clear_showcmd();
 | 
					    clear_showcmd();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3147,7 +3147,7 @@ bool add_to_showcmd(int c)
 | 
				
			|||||||
    K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
 | 
					    K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
 | 
				
			||||||
    K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT,
 | 
					    K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT,
 | 
				
			||||||
    K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
 | 
					    K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
 | 
				
			||||||
    K_CURSORHOLD,
 | 
					    K_EVENT,
 | 
				
			||||||
    0
 | 
					    0
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7567,16 +7567,11 @@ static void nv_open(cmdarg_T *cap)
 | 
				
			|||||||
    n_opencmd(cap);
 | 
					    n_opencmd(cap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					// Handle an arbitrary event in normal mode
 | 
				
			||||||
 * Trigger CursorHold event.
 | 
					static void nv_event(cmdarg_T *cap)
 | 
				
			||||||
 * 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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, false, curbuf);
 | 
					  queue_process_events(loop.events);
 | 
				
			||||||
  did_cursorhold = true;
 | 
					  cap->retval |= CA_COMMAND_BUSY;       // don't call edit() now
 | 
				
			||||||
  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.toplevel = toplevel;
 | 
				
			||||||
  s.oa = *oap;
 | 
					  s.oa = *oap;
 | 
				
			||||||
  normal_prepare(&s);
 | 
					  normal_prepare(&s);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  input_enable_events();
 | 
					  input_enable_events();
 | 
				
			||||||
  int c = safe_vgetc();
 | 
					  int c = safe_vgetc();
 | 
				
			||||||
  input_disable_events();
 | 
					  input_disable_events();
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (c == K_EVENT) {
 | 
					 | 
				
			||||||
    queue_process_events(loop.events);
 | 
					 | 
				
			||||||
    goto end;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  (void)normal_execute(&s, c);
 | 
					  (void)normal_execute(&s, c);
 | 
				
			||||||
 | 
					 | 
				
			||||||
end:
 | 
					 | 
				
			||||||
  *oap = s.oa;
 | 
					  *oap = s.oa;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,8 +36,8 @@ typedef struct oparg_S {
 | 
				
			|||||||
  bool block_mode;              /* current operator is Visual block mode */
 | 
					  bool block_mode;              /* current operator is Visual block mode */
 | 
				
			||||||
  colnr_T start_vcol;           /* start col for block mode operator */
 | 
					  colnr_T start_vcol;           /* start col for block mode operator */
 | 
				
			||||||
  colnr_T end_vcol;             /* end 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_opcount;            // ca.opcount saved for K_EVENT
 | 
				
			||||||
  long prev_count0;             /* ca.count0 saved for K_CURSORHOLD */
 | 
					  long prev_count0;             // ca.count0 saved for K_EVENT
 | 
				
			||||||
} oparg_T;
 | 
					} oparg_T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,6 +73,21 @@ void input_stop(void)
 | 
				
			|||||||
  stream_close(&read_stream, NULL);
 | 
					  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
 | 
					// Low level input function
 | 
				
			||||||
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
 | 
					int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -87,18 +102,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if ((result = inbuf_poll((int)p_ut)) == kInputNone) {
 | 
					    if ((result = inbuf_poll((int)p_ut)) == kInputNone) {
 | 
				
			||||||
      if (trigger_cursorhold() && maxlen >= 3
 | 
					      if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
 | 
				
			||||||
          && !typebuf_changed(tb_change_cnt)) {
 | 
					        create_cursorhold_event();
 | 
				
			||||||
        buf[0] = K_SPECIAL;
 | 
					      } else {
 | 
				
			||||||
        buf[1] = KS_EXTRA;
 | 
					 | 
				
			||||||
        buf[2] = KE_CURSORHOLD;
 | 
					 | 
				
			||||||
        return 3;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        before_blocking();
 | 
					        before_blocking();
 | 
				
			||||||
        result = inbuf_poll(-1);
 | 
					        result = inbuf_poll(-1);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // If input was put directly in typeahead buffer bail out here.
 | 
					  // If input was put directly in typeahead buffer bail out here.
 | 
				
			||||||
  if (typebuf_changed(tb_change_cnt)) {
 | 
					  if (typebuf_changed(tb_change_cnt)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -247,33 +247,21 @@ describe('vim_* functions', function()
 | 
				
			|||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        {1:very fail}                               |
 | 
					        {1:very fail}                               |
 | 
				
			||||||
      ]])
 | 
					      ]])
 | 
				
			||||||
 | 
					      helpers.wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      -- shows up to &cmdheight lines
 | 
					      -- shows up to &cmdheight lines
 | 
				
			||||||
      nvim_async('err_write', 'more fail\n')
 | 
					      nvim_async('err_write', 'more fail\ntoo fail\n')
 | 
				
			||||||
      nvim_async('err_write', 'too fail\n')
 | 
					 | 
				
			||||||
      screen:expect([[
 | 
					      screen:expect([[
 | 
				
			||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        ~                                       |
 | 
					        ~                                       |
 | 
				
			||||||
        {1:very fail}                               |
 | 
					 | 
				
			||||||
        {1:more 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}                                |
 | 
					        {1:too fail}                                |
 | 
				
			||||||
        {2:Press ENTER or type command to continue}^ |
 | 
					        {2:Press ENTER or type command to continue}^ |
 | 
				
			||||||
      ]])
 | 
					      ]])
 | 
				
			||||||
 | 
					      feed('<cr>')  -- exit the press ENTER screen
 | 
				
			||||||
    end)
 | 
					    end)
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user