|
|
@ -18,7 +18,6 @@ local vars = utils.vars
|
|
|
|
|
|
|
|
|
|
|
|
local mode = {}
|
|
|
|
local mode = {}
|
|
|
|
mode.ParseTable = require('libmodal/src/mode/ParseTable')
|
|
|
|
mode.ParseTable = require('libmodal/src/mode/ParseTable')
|
|
|
|
mode.TIMEOUT = 'TIMEOUT'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--[[
|
|
|
|
--[[
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@ -26,7 +25,16 @@ mode.TIMEOUT = 'TIMEOUT'
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
--]]
|
|
|
|
--]]
|
|
|
|
|
|
|
|
|
|
|
|
function mode._clearLocalInput(modeName)
|
|
|
|
local TIMEOUT_CHAR = 'ø'
|
|
|
|
|
|
|
|
local TIMEOUT_NR = api.nvim_eval("char2nr('" .. TIMEOUT_CHAR .. "')")
|
|
|
|
|
|
|
|
local TIMEOUT_LEN = api.nvim_get_option('TIMEOUT_LEN')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
--[[ SUMMARY:
|
|
|
|
|
|
|
|
* Reset libmodal's internal counter of user input to default.
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
local function clearLocalInput(modeName)
|
|
|
|
vars.input.instances[modeName] = {}
|
|
|
|
vars.input.instances[modeName] = {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
@ -38,11 +46,11 @@ end
|
|
|
|
* `modeName` => the name of the mode that is currently active.
|
|
|
|
* `modeName` => the name of the mode that is currently active.
|
|
|
|
]]
|
|
|
|
]]
|
|
|
|
------------------------------------
|
|
|
|
------------------------------------
|
|
|
|
function mode._comboSelect(modeName)
|
|
|
|
local function comboSelect(modeName)
|
|
|
|
-- Stop any running timers
|
|
|
|
-- Stop any running timers
|
|
|
|
if vars.timers.instances[modeName] then
|
|
|
|
if vars.timer.instances[modeName] then
|
|
|
|
vars.timers.instances[modeName]:stop()
|
|
|
|
vars.timer.instances[modeName]:stop()
|
|
|
|
vars.timers.instances[modeName] = nil
|
|
|
|
vars.timer.instances[modeName] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Append the latest input to the locally stored input history.
|
|
|
|
-- Append the latest input to the locally stored input history.
|
|
|
@ -53,9 +61,10 @@ function mode._comboSelect(modeName)
|
|
|
|
|
|
|
|
|
|
|
|
-- Get the combo dict.
|
|
|
|
-- Get the combo dict.
|
|
|
|
local comboTable = vars.combos.instances[modeName]
|
|
|
|
local comboTable = vars.combos.instances[modeName]
|
|
|
|
|
|
|
|
|
|
|
|
-- Get the command based on the users input.
|
|
|
|
-- Get the command based on the users input.
|
|
|
|
local cmd = comboTable:get(
|
|
|
|
local cmd = comboTable:get(
|
|
|
|
table.concat(vars.input.instance[modeName])
|
|
|
|
vars.input.instances[modeName]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
-- Get the type of the command.
|
|
|
|
-- Get the type of the command.
|
|
|
@ -67,21 +76,19 @@ function mode._comboSelect(modeName)
|
|
|
|
-- The command was a table, meaning that it MIGHT match.
|
|
|
|
-- The command was a table, meaning that it MIGHT match.
|
|
|
|
elseif commandType == globals.TYPE_TBL then
|
|
|
|
elseif commandType == globals.TYPE_TBL then
|
|
|
|
-- Create a new timer
|
|
|
|
-- Create a new timer
|
|
|
|
vars.timers.instances[modeName] = vim.loop.new_timer()
|
|
|
|
vars.timer.instances[modeName] = vim.loop.new_timer()
|
|
|
|
-- Get the `&timeoutlen` variable.
|
|
|
|
|
|
|
|
local timeoutlen = api.nvim_get_option('timeoutlen')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- start the timer
|
|
|
|
-- start the timer
|
|
|
|
vars.timers.instances[modeName]:start(timeoutlen, 0,
|
|
|
|
vars.timer.instances[modeName]:start(TIMEOUT_LEN, 0,
|
|
|
|
vim.schedule_wrap(function()
|
|
|
|
vim.schedule_wrap(function()
|
|
|
|
-- Send input to interrupt a blocking `getchar`
|
|
|
|
-- Send input to interrupt a blocking `getchar`
|
|
|
|
vim.api.nvim_feedkeys(mode.TIMEOUT, '', false)
|
|
|
|
api.nvim_feedkeys(TIMEOUT_CHAR, '', false)
|
|
|
|
-- if there is a command, execute it.
|
|
|
|
-- if there is a command, execute it.
|
|
|
|
if cmd[mode.ParseTable.CR] then
|
|
|
|
if cmd[mode.ParseTable.CR] then
|
|
|
|
api.nvim_command(cmd[mode.ParseTable.CR])
|
|
|
|
api.nvim_command(cmd[mode.ParseTable.CR])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- clear input
|
|
|
|
-- clear input
|
|
|
|
mode._clearLocalInput(modeName)
|
|
|
|
clearLocalInput(modeName)
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
-- The command was an actual vim command.
|
|
|
|
-- The command was an actual vim command.
|
|
|
@ -91,10 +98,38 @@ function mode._comboSelect(modeName)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
if clearInput then
|
|
|
|
if clearInput then
|
|
|
|
mode._clearLocalInput(modeName)
|
|
|
|
clearLocalInput(modeName)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-------------------------------------------------
|
|
|
|
|
|
|
|
--[[ SUMMARY:
|
|
|
|
|
|
|
|
* Set the initial values used for parsing user input as combos.
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
--[[ PARAMS:
|
|
|
|
|
|
|
|
* `modeName` => the name of the mode being initialized.
|
|
|
|
|
|
|
|
* `comboTable` => the table of combos being initialized.
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
-------------------------------------------------
|
|
|
|
|
|
|
|
local function initCombos(modeName, comboTable)
|
|
|
|
|
|
|
|
-- Placeholder for timeout value.
|
|
|
|
|
|
|
|
local doTimeout = nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Read the correct timeout variable.
|
|
|
|
|
|
|
|
if api.nvim_exists('g', vars.timeout.name(modeName)) then
|
|
|
|
|
|
|
|
doTimeout = vars.nvim_get(vars.timeout, modeName)
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
doTimeout = vars.libmodalTimeout
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
vars.timeout.instances[modeName] = doTimeout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Build the parse tree.
|
|
|
|
|
|
|
|
vars.combos.instances[modeName] = mode.ParseTable.new(comboTable)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Initialize the input history variable.
|
|
|
|
|
|
|
|
clearLocalInput(modeName)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
------------------------
|
|
|
|
------------------------
|
|
|
|
--[[ SUMMARY:
|
|
|
|
--[[ SUMMARY:
|
|
|
|
* Enter a mode.
|
|
|
|
* Enter a mode.
|
|
|
@ -111,7 +146,7 @@ function mode.enter(...)
|
|
|
|
--[[ SETUP. ]]
|
|
|
|
--[[ SETUP. ]]
|
|
|
|
|
|
|
|
|
|
|
|
-- Create the indicator for the mode.
|
|
|
|
-- Create the indicator for the mode.
|
|
|
|
local indicator = utils.Indicator:new(args[1])
|
|
|
|
local indicator = utils.Indicator.new(args[1])
|
|
|
|
|
|
|
|
|
|
|
|
-- Grab the state of the window.
|
|
|
|
-- Grab the state of the window.
|
|
|
|
local winState = utils.WindowState.new()
|
|
|
|
local winState = utils.WindowState.new()
|
|
|
@ -120,14 +155,14 @@ function mode.enter(...)
|
|
|
|
local modeName = string.lower(args[1])
|
|
|
|
local modeName = string.lower(args[1])
|
|
|
|
|
|
|
|
|
|
|
|
-- Determine whether or not this function should handle exiting automatically.
|
|
|
|
-- Determine whether or not this function should handle exiting automatically.
|
|
|
|
local handleExitEvents = false
|
|
|
|
local handleExitEvents = true
|
|
|
|
if #args > 2 and args[3] then
|
|
|
|
if #args > 2 then
|
|
|
|
handleExitEvents = true
|
|
|
|
handleExitEvents = args[3] == true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Determine whether a callback was specified, or a combo table.
|
|
|
|
-- Determine whether a callback was specified, or a combo table.
|
|
|
|
if type(args[2]) == globals.TYPE_TBL then
|
|
|
|
if type(args[2]) == globals.TYPE_TBL then
|
|
|
|
mode._initTimeouts(modeName, args[2])
|
|
|
|
initCombos(modeName, args[2])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--[[ MODE LOOP. ]]
|
|
|
|
--[[ MODE LOOP. ]]
|
|
|
@ -137,7 +172,7 @@ function mode.enter(...)
|
|
|
|
-- Try (using pcall) to use the mode.
|
|
|
|
-- Try (using pcall) to use the mode.
|
|
|
|
local noErrors = pcall(function()
|
|
|
|
local noErrors = pcall(function()
|
|
|
|
-- If the mode is not handling exit events automatically and the global exit var is true.
|
|
|
|
-- If the mode is not handling exit events automatically and the global exit var is true.
|
|
|
|
if not handleExitEvents and var.nvim_get(vars.exit, modeName) then
|
|
|
|
if not handleExitEvents and vars.nvim_get(vars.exit, modeName) then
|
|
|
|
continueMode = false
|
|
|
|
continueMode = false
|
|
|
|
return
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -147,9 +182,11 @@ function mode.enter(...)
|
|
|
|
|
|
|
|
|
|
|
|
-- Capture input.
|
|
|
|
-- Capture input.
|
|
|
|
local uinput = api.nvim_input()
|
|
|
|
local uinput = api.nvim_input()
|
|
|
|
|
|
|
|
|
|
|
|
-- Return if there was a timeout event.
|
|
|
|
-- Return if there was a timeout event.
|
|
|
|
if uinput == mode.TIMEOUT then return end
|
|
|
|
if uinput == TIMEOUT_NR then return end
|
|
|
|
-- Otherwise set the input variable to the new input.
|
|
|
|
|
|
|
|
|
|
|
|
-- Set the global input variable to the new input.
|
|
|
|
vars.nvim_set(vars.input, modeName, uinput)
|
|
|
|
vars.nvim_set(vars.input, modeName, uinput)
|
|
|
|
|
|
|
|
|
|
|
|
-- Make sure that the user doesn't want to exit.
|
|
|
|
-- Make sure that the user doesn't want to exit.
|
|
|
@ -158,17 +195,14 @@ function mode.enter(...)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
-- If the second argument was a dict, parse it.
|
|
|
|
-- If the second argument was a dict, parse it.
|
|
|
|
elseif type(args[2]) == globals.TYPE_TBL then
|
|
|
|
elseif type(args[2]) == globals.TYPE_TBL then
|
|
|
|
mode._comboSelect(modeName)
|
|
|
|
comboSelect(modeName)
|
|
|
|
-- If the second argument was a function, execute it.
|
|
|
|
-- If the second argument was a function, execute it.
|
|
|
|
else
|
|
|
|
else args[2]() end
|
|
|
|
args[2]()
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
-- If there were errors, handle them.
|
|
|
|
-- If there were errors, handle them.
|
|
|
|
if not noErrors then
|
|
|
|
if not noErrors then
|
|
|
|
mode._showError()
|
|
|
|
utils.showError()
|
|
|
|
continueMode = false
|
|
|
|
continueMode = false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -180,40 +214,10 @@ function mode.enter(...)
|
|
|
|
winState:restore()
|
|
|
|
winState:restore()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function mode._initTimeouts(modeName, comboTable)
|
|
|
|
|
|
|
|
-- Placeholder for timeout value.
|
|
|
|
|
|
|
|
local doTimeout = nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Read the correct timeout variable.
|
|
|
|
|
|
|
|
if api.nvim_exists('g', vars.timeout.name(modeName)) then
|
|
|
|
|
|
|
|
doTimeout = vars.nvim_get(vars.timeout, modeName)
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
doTimeout = vars.libmodalTimeout
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
vars.timeout.instances[modeName] = doTimeout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Build the parse tree.
|
|
|
|
|
|
|
|
vars.combos.instances[modeName] = mode.ParseTable.new(comboTable)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Initialize the input history variable.
|
|
|
|
|
|
|
|
mode._clearLocalInput(modeName)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function mode._showError()
|
|
|
|
|
|
|
|
api.nvim_bell()
|
|
|
|
|
|
|
|
api.nvim_show_err( 'vim-libmodal error',
|
|
|
|
|
|
|
|
api.nvim_get_vvar('throwpoint')
|
|
|
|
|
|
|
|
.. '\n' ..
|
|
|
|
|
|
|
|
api.nvim_get_vvar('exception')
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--[[
|
|
|
|
--[[
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* PUBLICIZE MODULE
|
|
|
|
* PUBLICIZE MODULE
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
--]]
|
|
|
|
--]]
|
|
|
|
|
|
|
|
|
|
|
|
mode.enter('test', {})
|
|
|
|
|
|
|
|
return mode
|
|
|
|
return mode
|
|
|
|
|
|
|
|
|
|
|
|