Full commit with working app
parent
9a4c929eb8
commit
9e51e33869
@ -0,0 +1 @@
|
||||
doc/tags
|
@ -0,0 +1,162 @@
|
||||
<div align="center">
|
||||
# DelayTrain
|
||||
_Train yourself to stop repeating keys... gently_
|
||||
|
||||
[How does it work?](#how-does-it-work) • [Installation](#installation)
|
||||
• [Configuration](#configuration) • [Commands](#commands)
|
||||
• [Contributing](#contributing)
|
||||
|
||||
TODO: quick demo gif ~/Videos/delaytrain.gif
|
||||
</div>
|
||||
|
||||
## "Stop using arrow keys!" "Stop using hjkl!"
|
||||
|
||||
If you're familiar with the (neo)vim community you've probably heard this a
|
||||
million times. The whole point of vim is to seamlessly navigate where you
|
||||
need to go without constantly repeating keypresses. Why press `j` ten times
|
||||
when you can press `10j`, or `}`, or search.
|
||||
|
||||
But if you've been using vim for a while this may be a harder habit to break.
|
||||
You try to stop relying on this type of navigation but you only catch
|
||||
yourself after the fact. You might chastize yourself and move on but the
|
||||
habit stays there.
|
||||
|
||||
Most recommendations involve disabling these keys altogether, but this only
|
||||
increases frustration. Sometimes your next position is directly above and
|
||||
the quickest option is to press `k`. This might help in the long run but
|
||||
it's incredibly annoying and hard to stick with.
|
||||
|
||||
That's where DelayTrain comes in.
|
||||
|
||||
DelayTrain will still let you use these keybindings, but it only punishes
|
||||
you when you _keep_ hitting them. If you need to navigate directly below,
|
||||
you can still do that. But if you need to navigate 5 lines below using
|
||||
repeated keypresses, DelayTrain will gently remind you that there might
|
||||
be a better way by stopping the keypress from working for a certain
|
||||
amount of time.
|
||||
|
||||
And DelayTrain doesn't just work for hjkl. Mappings are included to
|
||||
prevent repeated arrow key presses and you can configure delaytrain to
|
||||
prevent anything else like `w` or `b`.
|
||||
|
||||
## How does it work?
|
||||
|
||||
DelayTrain takes two configurable values, `delay_ms` and `grace_period`.
|
||||
|
||||
When you first hit a configured keypress (like `j`), the `delay_ms` timer
|
||||
starts. You are given a `grace_period` of repeated keypresses within the
|
||||
`delay_ms` timer before the key stops working. Once the `delay_ms` timer
|
||||
ends, everything is reset.
|
||||
|
||||
### Examples
|
||||
|
||||
We'll use a few tables to show how this works. Assume the follwing:
|
||||
|
||||
* `delay_ms = 1000`
|
||||
* `grace_period = 2`
|
||||
|
||||
By default the `grace_period` is 1, but setting it to 2 allows you to
|
||||
press the key twice before it stops working.
|
||||
|
||||
| Keypress | Time | Grace Period | Does it work? |
|
||||
| ---------- | ----------- | ------------ | ------------- |
|
||||
| `j` | 0ms | 1 | Yes |
|
||||
| `j` | 200ms | 2 | Yes |
|
||||
| `j` | 500ms | 3 | No |
|
||||
| `j` | 1000ms | 1 | Yes |
|
||||
|
||||
Each keypress starts a dedicated `delay_ms` timer and has a dedicated
|
||||
`grace_period`. So if you're trying to navigate down and to the left,
|
||||
this still works.
|
||||
|
||||
| Keypress | Time | Grace Period | Does it work? |
|
||||
| ---------- | ----------- | ------------ | ------------- |
|
||||
| `j' | 0ms | 1 | Yes |
|
||||
| `j' | 200ms | 2 | Yes |
|
||||
| `h' | 500ms | 1 | Yes |
|
||||
| `j' | 700ms | 3 | No |
|
||||
| `h' | 1000ms | 2 | Yes |
|
||||
| `j' | 1200ms | 1 | Yes |
|
||||
| `h' | 1400ms | 3 | No |
|
||||
| `h' | 1500ms | 1 | Yes |
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Install with [vim-plug](https://github.com/junegunn/vim-plug):
|
||||
|
||||
```vim
|
||||
Plug '[TODO GITHUB NAME]/delaytrain.nvim'
|
||||
```
|
||||
|
||||
or with [packer](https://github.com/wbthomason/packer.nvim):
|
||||
|
||||
```lua
|
||||
-- Delay repeat execution of certain keys
|
||||
use '[TODO GITHUB NAME]/delaytrain.nvim'
|
||||
```
|
||||
|
||||
For the default setup (see defaults below), you can simply place the following
|
||||
into your `init.lua`:
|
||||
|
||||
```lua
|
||||
require('delaytrain').setup()
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure all DelayTrain settings through the `setup()` function. The
|
||||
default DelayTrain mappings are included below:
|
||||
|
||||
```lua
|
||||
require('delaytrain').setup {
|
||||
delay_ms = 1000, -- How long repeated usage of a key should be prevented
|
||||
grace_period = 1, -- How many repeated keypresses are allowed
|
||||
keys = { -- Which keys (in which modes) should be delayed
|
||||
['nv'] = {'h', 'j', 'k', 'l'},
|
||||
['nvi'] = {'<Left>', '<Down>', '<Up>', '<Right>'},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Mappings
|
||||
|
||||
The keys option allows you to delay different keypresses in different modes.
|
||||
This takes the following KV pair:
|
||||
|
||||
```lua
|
||||
['list_of_applicable_modes'] = {'keys', 'you', 'want', 'delayed'},
|
||||
```
|
||||
|
||||
Modes can be added based on their short-names (ex: normal is 'n', insert is
|
||||
'i') and multiple modes can be added to a single keymap.
|
||||
|
||||
This option ties into a call to `vim.keymap.set()`, so mode short-names and
|
||||
key names should match what is possible in that function.
|
||||
|
||||
### Options
|
||||
|
||||
Global options can be modified to change delay/grace period settings on the
|
||||
fly:
|
||||
|
||||
* `g:delaytrain_delay_ms`
|
||||
* `g:delaytrain_grace_period`
|
||||
|
||||
## Commands
|
||||
|
||||
The following commands allow you to turn DelayTrain on and off without
|
||||
calling `setup()` again:
|
||||
|
||||
* `:DelayTrainEnable`
|
||||
* `:DelayTrainDisable`
|
||||
* `:DelayTrainToggle`
|
||||
|
||||
By default, DelayTrain is turned on when the `setup()` function is called.
|
||||
|
||||
## Contributing
|
||||
|
||||
This has been tested on my personal and work machines using nvim-nightly and
|
||||
[Neovide](https://github.com/neovide/neovide). This is a REALLY SMALL plugin
|
||||
so while there shouldn't be a lot of issues it's entirely possible I missed
|
||||
something. I'm also brand new to plugin development so if you notice anything
|
||||
off please feel free to open up an issue or send me a PR!
|
@ -0,0 +1,118 @@
|
||||
*delaytrain.txt* DelayTrain
|
||||
*delaytrain.nvim*
|
||||
|
||||
Author: James Ford <james@jamesford.io>
|
||||
Version: 1.0.0
|
||||
Homepage: <>
|
||||
|
||||
=============================================================================
|
||||
INTRODUCTION *delaytrain*
|
||||
|
||||
When learning how to use Vim keybindings, sometimes it's helpful to avoid
|
||||
repetitive keypresses. For example, repetitive use of hjkl or arrow keys can
|
||||
often be replaced with a numeric prefix, or an even better key to navigate
|
||||
exactly where you want to go.
|
||||
|
||||
To help train your muscle memory, most people suggest un-mapping these keys
|
||||
to avoid using them completely. But there are certain cases where hjkl may
|
||||
be necessary and another key combination would be overkill.
|
||||
|
||||
DelayTrain helps train this muscle memory by preventing a keypress from
|
||||
being used after a certain amount of repeated usage inside a timeframe,
|
||||
rather than disabling the key completely. This way you can still go about
|
||||
your work with a gentle reminder that there might be a better way to do
|
||||
what you want.
|
||||
|
||||
==============================================================================
|
||||
USAGE *delaytrain-usage*
|
||||
|
||||
Most people will be training with hjkl and arrow keys, so for a default setup
|
||||
you can simply run:
|
||||
>
|
||||
require('delaytrain').setup()
|
||||
<
|
||||
|
||||
==============================================================================
|
||||
CONFIGURATION *delaytrain-configuration*
|
||||
|
||||
For more granular configuration and additional keymaps, you can pass the
|
||||
following configuration (default settings included):
|
||||
>
|
||||
require('delaytrain').setup {
|
||||
delay_ms = 1000, -- How long repeated usage of a key should be prevented
|
||||
grace_period = 1, -- How many repeated keypresses are allowed
|
||||
keys = { -- Which keys (in which modes) should be delayed
|
||||
['nv'] = {'h', 'j', 'k', 'l'},
|
||||
['nvi'] = {'<Left>', '<Down>', '<Up>', '<Right>'},
|
||||
},
|
||||
}
|
||||
<
|
||||
Keep in mind that the `delay_ms` timer starts on the FIRST keypress and not the
|
||||
final `grace_period` keypress. For example (with default settings) if you hit j,
|
||||
the timer starts immediately. If you hit j again after 500ms, the key will not
|
||||
work. If you wait ANOTHER 500ms and hit j again, it will work. Likewise, if
|
||||
you hit j, wait 1000ms, and hit j again, both keypresses will work.
|
||||
|
||||
With an increased `grace_period`, you can hit a key `grace_period` amount of times
|
||||
inside `delay_ms` before it stops working.
|
||||
|
||||
`grace_period` and `delay_ms` only affect the current key being pressed. With
|
||||
the default settings, if you hit j and then hit k after 500ms, both keypresses
|
||||
will work. If you wait another 200ms and hit j again, the keypress will not
|
||||
work.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
MAPPINGS *delaytrain-mappings*
|
||||
|
||||
The keys option allows you to delay different keypresses in different modes.
|
||||
This takes the following KV pair:
|
||||
>
|
||||
['list_of_applicable_modes'] = {'keys', 'you', 'want', 'delayed'},
|
||||
<
|
||||
Modes can be added based on their short-names (ex: normal is 'n', insert is
|
||||
'i') and multiple modes can be added to a single keymap.
|
||||
|
||||
This option ties into a call to |vim.keymap.set()|, so mode short-names and
|
||||
key names should match what is possible in that function.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
OPTIONS *delaytrain-options*
|
||||
|
||||
Global options can be modified to change delay/grace period settings on the
|
||||
fly.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
g:delaytrain_delay_ms~ *g:delaytrain_delay_ms*
|
||||
|
||||
How long repeated usage of a key should be prevented. Keep in mind that the
|
||||
timer starts on the FIRST keypress and delays repeated usage of a key based on
|
||||
`grace_period` in this timeframe.
|
||||
|
||||
Type: |Number|
|
||||
Default value: `1000`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
g:delaytrain_grace_period~ *g:delaytrain_grace_period*
|
||||
|
||||
How many repeated keypresses are allowed inside the `delay_ms` timeframe. By
|
||||
default this is 1, so you can press a key 1 time inside `delay_ms` before it's
|
||||
disabled. Setting this value to 0 will completely disable the key.
|
||||
|
||||
Type: |Number|
|
||||
Default value: `1`
|
||||
|
||||
==============================================================================
|
||||
COMMANDS *delaytrain-commands*
|
||||
|
||||
:DelayTrainEnable *:DelayTrainEnable*
|
||||
Enable DelayTrain by setting defined keymaps
|
||||
|
||||
:DelayTrainDisable *:DelayTrainDisable*
|
||||
Disable DelayTrain by deleting defined keymaps
|
||||
|
||||
:DelayTrainToggle *:DelayTrainToggle*
|
||||
Toggle DelayTrain by setting/deleting keymaps
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
@ -0,0 +1,96 @@
|
||||
local M = {}
|
||||
|
||||
vim.g.delaytrain_delay_ms = 1000
|
||||
vim.g.delaytrain_grace_period = 1
|
||||
|
||||
-- Map of keys to their individual current grace period
|
||||
-- This keeps track of how many times a key has been pressed
|
||||
local current_grace_period_intervals = {}
|
||||
|
||||
local keymaps = {
|
||||
['nv'] = {'h', 'j', 'k', 'l'},
|
||||
['nvi'] = {'<Left>', '<Down>', '<Up>', '<Right>'},
|
||||
}
|
||||
|
||||
local is_enabled = false
|
||||
|
||||
function M.try_delay_keypress(key)
|
||||
current_interval = current_grace_period_intervals[key]
|
||||
|
||||
-- Start a timer on the first keypress to reset the interval
|
||||
if current_interval == 0 then
|
||||
vim.loop.new_timer():start(vim.g.delaytrain_delay_ms, 0, function()
|
||||
current_grace_period_intervals[key] = 0
|
||||
end)
|
||||
end
|
||||
|
||||
-- Pass the key through only if we haven't reached the grace period
|
||||
if current_interval < vim.g.delaytrain_grace_period then
|
||||
current_grace_period_intervals[key] = current_interval + 1
|
||||
|
||||
vim.api.nvim_feedkeys(
|
||||
vim.api.nvim_replace_termcodes(key, true, false, true),
|
||||
'n',
|
||||
false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
if opts then
|
||||
if opts.delay_ms then
|
||||
vim.g.delaytrain_delay_ms = opts.delay_ms
|
||||
end
|
||||
|
||||
if opts.grace_period then
|
||||
vim.g.delaytrain_grace_period = opts.grace_period
|
||||
end
|
||||
|
||||
if opts.keys then
|
||||
keymaps = opts.keys
|
||||
end
|
||||
end
|
||||
|
||||
M.enable()
|
||||
end
|
||||
|
||||
function M.enable()
|
||||
is_enabled = true
|
||||
|
||||
for modes, keys in pairs(keymaps) do
|
||||
mode_array = {}
|
||||
for mode in modes:gmatch"." do
|
||||
table.insert(mode_array, mode)
|
||||
end
|
||||
for _, key in ipairs(keys) do
|
||||
-- Set the current grace period for the given key
|
||||
current_grace_period_intervals[key] = 0
|
||||
|
||||
vim.keymap.set(mode_array, key, function() M.try_delay_keypress(key) end, {expr = true})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.disable()
|
||||
is_enabled = false
|
||||
|
||||
for modes, keys in pairs(keymaps) do
|
||||
mode_array = {}
|
||||
for mode in modes:gmatch"." do
|
||||
table.insert(mode_array, mode)
|
||||
end
|
||||
for _, key in ipairs(keys) do
|
||||
vim.keymap.del(mode_array, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.toggle()
|
||||
if is_enabled then
|
||||
M.disable()
|
||||
else
|
||||
M.enable()
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,11 @@
|
||||
vim.api.nvim_create_user_command("DelayTrainEnable", function()
|
||||
require("delaytrain").enable()
|
||||
end, { desc = "Enable DelayTrain by setting defined keymaps" })
|
||||
|
||||
vim.api.nvim_create_user_command("DelayTrainDisable", function()
|
||||
require("delaytrain").disable()
|
||||
end, { desc = "Disable DelayTrain by deleting defined keymaps" })
|
||||
|
||||
vim.api.nvim_create_user_command("DelayTrainToggle", function()
|
||||
require("delaytrain").toggle()
|
||||
end, { desc = "Toggle DelayTrain by setting/deleting keymaps" })
|
Loading…
Reference in New Issue