- Declarative: configure cursors with ease of lua tables
- Triggers: change cursor colors/shape/size/blink on specific triggers
- Trigger strategies: select one of two available strategies or build your own
- Complete: support for all native cursor settings
- With
lazy.nvim
:
{
'rasulomaroff/cursor.nvim',
event = 'VeryLazy',
opts = {
-- Your options go here
}
}
---@type Cursor.Config
{
overwrite_cursor = false,
cursors = nil,
trigger = {
strategy = nil,
cursors = nil,
},
}
config.overwrite_cursor
: boolean
Default: false
.
If true
, then it will clear vim.opt.guicursor
when the setup
method is called. This allows you to configure
cursors from scratch.
config.cursors
: table<string | Cursor.Cursor>
It is an array of cursor strings (:h 'guicursor'
) or lua tables with the following type:
Cursor.Cursor
-
mode
- required. mode in which a cursor will be applied, check:h 'guicursor'
. -
shape
-'block'
|'ver'
|'hor'
- shape of a cursor: block, vertical or horizontal. -
size
-number
from 1 to 100. Will only work in GUI. Ignored for theblock
shape. -
hl
-string
|[string, string]
- Highlight group or groups which will be used to highlight a cursor. If a tuple specified, then the second value is used to highlight language mappings. Read more:h language-mapping
. -
replace
-boolean
- remove this cursor while a trigger is active.default
: false. -
blink
-number
|false
|Cursor.Cursor.Blink
- If specified asnumber
, then that number will be used forblinkwait
,blinkon
,blinkoff
. If specified asfalse
, then it will forcely disable blinking (the use-case of this will be presented below). Or can be specified as a table with the following type:Cursor.Cursor.Blink
wait
-number
ms - blinkwaiton
-number
ms - blinkonoff
-number
ms - blinkoffdefault
-number
ms - this value will be used if any of the fields above aren't specified
You can read about all of the above options in
:h 'guicursor'
Warn: all of those blink options are supposed to work in GUI. You can still set numbers there to enable blinking in general, but in most cases it won't matter which number you specify. Don't forget if you set
0
for any of those fields, it will disable blinking completely (:h 'guicursor'
)
config.trigger.cursors
: table<Cursor.Cursor | string>
It is an array of cursor strings (:h 'guicursor'
) or lua tables with the same type as config.cursors
, except it doesn't
have replace
property. Every other field is applicable. These cursors will be applied on specific triggers and revoked after those
triggers are gone.
config.trigger.strategy.type
: 'event'
| 'timer'
| 'custom'
Default: nil
Specifies a strategy type.
Timer strategy type - 'timer'
config.trigger.strategy.timer
: Cursor.Strategy.Timer
This field will be used only if config.trigger.strategy.type='timer'
. It will use a timer to revoke cursors and events to trigger them.
By default cursors are triggered on CursorMoved
and CursorMovedI
events, but you can replace/extend them.
Cursor.Strategy.Timer
delay
:number
- delay in ms after which cursor will be revoked. Default:5000
.events
:table<string>
- array of events that will trigger cursors applying. They will extend default ones (CursorMovedI
,CursorMoved
).overwrite_events
:boolean
- remove default events from theevents
field. Default:false
.
Event strategy type - 'event'
This type of strategy doesn't have a config. It will be triggered on CursorMoved
and CursorMovedI
events and set cursors. Cursors will be unset on
CursorHold
and CursorHoldI
events.
The time between
CursorMoved
andCursorHold
events are specified byvim.opt.updatetime
.
Custom strategy type - 'custom'
Custom strategy type allows you to control when cursors are applied and revoked. You can read more on this below.
You can build your custom trigger system and then call trigger/revoke methods to apply/delete the cursors you specified:
- You need to setup the plugin to use the "custom" strategy and specify regular and trigger cursors.
require('cursor').setup {
cursors = {
-- put your regular cursors here
},
trigger = {
strategy = {
-- use custom strategy
type = 'custom',
},
cursors = {
-- put cursors that will be set while trigger is active here
}
}
- Require the
cursor
table with 2 mentioned methods:
local cursor = require('cursor.strategy.custom')
- Use those methods with your custom triggers:
- You can use events to trigger your cursors:
vim.api.nvim_create_autocmd('InsertEnter', {
callback = cursor.trigger
})
vim.api.nvim_create_autocmd('InsertLeave', {
callback = cursor.revoke
})
- Or you can call methods from anywhere you want
local function custom()
-- other code
cursor.trigger()
-- other code
end
Advice: don't forget about the
replace
property when specifying regular cursors. It will allow you to remove those cursors while your triggers are active.
If you call the
trigger
method twice without calling therevoke
method between them, nothing bad will happen, cursors won't be applied twice. These cases are handled correctly, the same goes to calling therevoke
method twice.
- Set cursors in all mode to have the
block
shape.
require('cursor').setup {
overwrite_cursor = true,
cursors = {
{
mode = 'a',
shape = 'block'
}
}
}
- The example below will unset blinking on
CursorMoved
andCursorMovedI
events and set it onCursorHold
andCursorHoldI
events.
require('cursor').setup {
cursors = {
{
mode = 'a',
blink = { wait = 100, default = 400 },
},
},
trigger = {
strategy = {
type = 'event',
},
cursors = {
{
mode = 'a',
blink = false,
},
},
},
}
- The example below will highlight your cursor on the same events as the example above and remove highlights as well.
require('cursor').setup {
trigger = {
strategy = {
type = 'event'
},
cursors = {
{
mode = 'a',
hl = 'YourHighlight'
}
}
}
}
- Revoke trigger cursors after 10 seconds after triggering
require('cursor').setup {
cursors = {
{
mode = 'a',
shape = 'block'
},
},
trigger = {
strategy = {
type = 'timer',
timer = {
delay = 10000
}
},
cursors = {
{
mode = 'a',
blink = 500,
hl = 'YourHighlight'
}
}
}
}
- WezTerm - blinking times don't affect cursor blinking times, which is expected, but blinking overall works. You can configure blinking delay in the WezTerm config file. Tested on MacOS.
- Alacritty - blinking stops after several blinks even without using this plugin, not sure why. Tested on MacOS.
- iTerm - the same as WezTerm.
- Neovide - everything works perfectly. Tested on MacOS.