You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nvim-libmodal/lua/libmodal/src/Prompt.lua

206 lines
4.8 KiB
Lua

--[[
/*
* IMPORTS
*/
--]]
4 years ago
local globals = require('libmodal/src/globals')
local Indicator = require('libmodal/src/Indicator')
local Stack = require('libmodal/src/collections/Stack')
local utils = require('libmodal/src/utils')
local Vars = require('libmodal/src/Vars')
local api = utils.api
--[[
/*
* MODULE
*/
--]]
local Prompt = {}
local _HELP = 'help'
local _replacements = {
'(', ')', '[', ']', '{', '}',
'=', '+', '<', '>', '^',
',', '/', ':', '?', '@', '!', '$', '*', '.', '%', '&', '\\',
}
--[[
/*
* META `Prompt`
*/
--]]
local _metaPrompt = {}
_metaPrompt.__index = _metaPrompt
_metaPrompt._indicator = nil
_metaPrompt._input = nil
_metaPrompt._instruction = nil
_metaPrompt._name = nil
function _metaPrompt:_inputLoop()
-- clear previous `echo`s.
api.nvim_redraw()
-- get user input based on `instruction`.
local userInput = ''
if self._completions then userInput =
api.nvim_call_function('libmodal#_inputWith', {
self._indicator, self._completions
})
else userInput =
api.nvim_call_function('input', {
self._indicator
})
end
-- if a:2 is a function then call it.
if string.len(userInput) > 0 then
self._input:nvimSet(self._name, userInput)
if type(self._instruction) == globals.TYPE_TBL then
if self._instruction[userInput] then -- there is a defined command for the input.
api.nvim_command(instruction[userInput])
elseif userInput == _HELP then -- the user did not define a 'help' command, so use the default.
self._help:show()
else -- show an error.
api.nvim_show_err(globals.DEFAULT_ERROR_TITLE, 'Unknown command')
end
else instruction()
end
else return false
end
return true
end
function _metaPrompt:enter()
-- enter the mode using a loop.
local continueMode = true
while continueMode == true do
local noErrors, result = pcall(self._inputLoop, self)
-- if there were errors.
if not noErrors then
utils.showError(err)
continueMode = false
else
continueMode = result
end
end
end
--[[
/*
* CLASS `Prompt`
*/
--]]
------------------------------------------------------
--[[ SUMMARY:
* Provide completions for a `libmodal.prompt`.
]]
--[[ PARAMS:
* `completions` => the list of completions.
]]
--[[ RETURNS:
* A function that accepts:
* `argLead` => the current line being edited, stops at the cursor.
* `cmdLine` => the current line being edited
* `cursorPos` => the position of the cursor
* Used for `input()` VimL.
]]
------------------------------------------------------
function Prompt.createCompletionsProvider(completions)
return function(argLead, cmdLine, cursorPos)
if string.len(cmdLine) < 1 then
return completions
end
-- replace conjoining characters with spaces.
local spacedArgLead = argLead
for _, v in ipairs(_replacements) do
spacedArgLead, _ = string.gsub(spacedArgLead, vim.pesc(v), ' ')
end
-- split the spaced version of `argLead`.
local splitArgLead = vim.split(spacedArgLead, ' ', true)
-- make sure the user is in a position were this function
-- will provide accurate completions.
if #splitArgLead > 1 then
return nil
end
-- get the word selected by the user. (don't compare case)
local word = string.upper(splitArgLead[1])
-- get all matches from the completions list.
local matches = {}
for _, v in ipairs(completions) do
-- test if `word` is inside of `completions`:`v`, ignoring case.
if string.match(vim.pesc(string.upper(v)), word) then
matches[#matches + 1] = v -- preserve case when providing completions.
end
end
return matches
end
end
-------------------------------------------
--[[ SUMMARY:
* Enter a prompt.
]]
--[[ PARAMS:
* `name` => the prompt name.
* `instruction` => the prompt callback, or mode command table.
* `...` => a completions table.
]]
-------------------------------------------
function Prompt.new(name, instruction, ...)
self = {}
setmetatable(self, _metaPrompt)
4 years ago
self._indicator = Indicator.prompt(name)
self._input = vars.new('input')
self._instruction = instruction
self._name = name
-- get the arguments
local userCompletions = unpack({...})
-- get the completion list.
if type(instruction) == globals.TYPE_TBL then -- unload the keys of the mode command table.
-- Create one if the user specified a command table.
local completions = {}
local containedHelp = false
for k, _ in pairs(instruction) do
completions[#completions + 1] = k
if k == _HELP then containedHelp = true
end
end
if not containedHelp then -- assign it.
completions[#completions + 1] = _HELP
vars.help.instances[modeName] = utils.Help.new(instruction, 'COMMAND')
end
self._completions = completions
elseif userCompletions then
-- Use the table that the user gave.
self._completions = userCompletions
end
end
--[[
/*
* PUBLICIZE MODULE
*/
--]]
return Prompt