Initial conversion of prompt
parent
7c2f9694d8
commit
523261dcbc
@ -0,0 +1,82 @@
|
||||
--[[
|
||||
/*
|
||||
* MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
local Indicator = {}
|
||||
|
||||
Indicator.HighlightSegment = require('libmodal/src/Indicator/HighlightSegment')
|
||||
|
||||
-- highlight group names
|
||||
local _HL_GROUP_PROMPT = 'LibmodalPrompt'
|
||||
local _HL_GROUP_STAR = 'LibmodalStar'
|
||||
local _HL_GROUP_NONE = 'None'
|
||||
|
||||
-- `libmodal.mode` `HighlightSegment`s.
|
||||
local _ENTRY_MODE_START = Indicator.HighlightSegment.new(_HL_GROUP_PROMPT, '-- ')
|
||||
local _ENTRY_MODE_END = Indicator.HighlightSegment.new(_HL_GROUP_PROMPT, ' --')
|
||||
|
||||
-- `libmodal.prompt` `HighlightSegment`s.
|
||||
local _ENTRY_PROMPT_START = Indicator.HighlightSegment.new(_HL_GROUP_STAR, '* ')
|
||||
local _ENTRY_PROMPT_END = Indicator.HighlightSegment.new(_HL_GROUP_PROMPT, ' > ')
|
||||
|
||||
--[[
|
||||
/*
|
||||
* META `Indicator`
|
||||
*/
|
||||
--]]
|
||||
|
||||
local _metaIndicator = {
|
||||
_ENTRY_MODE_START, nil, _ENTRY_MODE_END
|
||||
}
|
||||
_metaIndicator.__index = _metaIndicator
|
||||
|
||||
local _PROMPT_TEMPLATE = {
|
||||
'* ', ' > '
|
||||
}
|
||||
|
||||
--[[
|
||||
/*
|
||||
* CLASS `Indicator`
|
||||
*/
|
||||
--]]
|
||||
|
||||
---------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new `Indicator` for a mode.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `modeName` => the name of the mode that this `Indicator` is for.
|
||||
]]
|
||||
---------------------------------
|
||||
function Indicator.mode(modeName)
|
||||
local self = {}
|
||||
setmetatable(self, _metaIndicator)
|
||||
|
||||
self[2] = Indicator.HighlightSegment.new(
|
||||
_HL_GROUP_PROMPT, tostring(modeName)
|
||||
)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-----------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new `Indicator` for a prompt.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `modeName` => the name of the mode that this `Indicator` is for.
|
||||
]]
|
||||
-----------------------------------
|
||||
function Indicator.prompt(modeName)
|
||||
return table.concat(_PROMPT_TEMPLATE, modeName)
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* PUBLICIZE MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
return Indicator
|
@ -0,0 +1,204 @@
|
||||
--[[
|
||||
/*
|
||||
* IMPORTS
|
||||
*/
|
||||
--]]
|
||||
|
||||
local globals = require('libmodal/src/globals')
|
||||
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)
|
||||
|
||||
self._indicator = utils.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
|
@ -0,0 +1,83 @@
|
||||
--[[
|
||||
/*
|
||||
* MODULE `Stack`
|
||||
*/
|
||||
--]]
|
||||
|
||||
local Stack = {}
|
||||
|
||||
--[[
|
||||
/*
|
||||
* META `Stack`
|
||||
*/
|
||||
--]]
|
||||
|
||||
local _metaStack = {}
|
||||
_metaStack.__index = _metaStack
|
||||
|
||||
_metaStack._len = 0
|
||||
_metaStack._top = nil
|
||||
|
||||
--------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Get the foremost value in `self`.
|
||||
]]
|
||||
--[[
|
||||
* The foremost value in `self`.
|
||||
]]
|
||||
--------------------------------
|
||||
function _metaStack:peek()
|
||||
return top
|
||||
end
|
||||
|
||||
-------------------------
|
||||
--[[ SUMMARY:
|
||||
* Remove the foremost value in `self` and return it.
|
||||
]]
|
||||
--[[ RETURNS:
|
||||
* The foremost value in `self`.
|
||||
]]
|
||||
-------------------------
|
||||
function _metaStack:pop()
|
||||
if len < 1 then return nil
|
||||
end
|
||||
|
||||
-- Store the previous top of the stack.
|
||||
local previousTop = self._top
|
||||
|
||||
-- Remove the previous top of the stack.
|
||||
self[_len] = nil
|
||||
|
||||
-- Update the values of the stack.
|
||||
self._len = self._len - 1
|
||||
self._top = self[_len]
|
||||
|
||||
-- Return the previous top of the stack.
|
||||
return previousTop
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Push some `value` onto `self`.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `value` => the value to append to `self`.
|
||||
]]
|
||||
-------------------------------
|
||||
function _metaStack:push(value)
|
||||
self._len = self._len + 1
|
||||
self[_len] = value
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* CLASS `Stack`
|
||||
*/
|
||||
--]]
|
||||
|
||||
function Stack.new()
|
||||
local self = {}
|
||||
setmetatable(self, _metaStack)
|
||||
|
||||
return self
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
local collections = {}
|
||||
collections.Stack = require('libmodal/src/collections/Stack')
|
||||
return collections
|
@ -1,70 +0,0 @@
|
||||
--[[
|
||||
/*
|
||||
* IMPORTS
|
||||
*/
|
||||
--]]
|
||||
|
||||
local Entry = require('libmodal/src/utils/Indicator/Entry')
|
||||
|
||||
--[[
|
||||
/*
|
||||
* MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
local Indicator = {}
|
||||
|
||||
-- highlight group names
|
||||
local _HL_GROUP_PROMPT = 'LibmodalPrompt'
|
||||
local _HL_GROUP_STAR = 'LibmodalStar'
|
||||
local _HL_GROUP_NONE = 'None'
|
||||
|
||||
-- `libmodal.mode` `Entry`s.
|
||||
local _ENTRY_MODE_START = Entry.new(_HL_GROUP_PROMPT, '-- ')
|
||||
local _ENTRY_MODE_END = Entry.new(_HL_GROUP_PROMPT, ' --')
|
||||
|
||||
-- `libmodal.prompt` `Entry`s.
|
||||
local _ENTRY_PROMPT_START = Entry.new(_HL_GROUP_STAR, '* ')
|
||||
local _ENTRY_PROMPT_END = Entry.new(_HL_GROUP_PROMPT, ' > ')
|
||||
|
||||
--[[
|
||||
/*
|
||||
* CLASS `Indicator`
|
||||
*/
|
||||
--]]
|
||||
|
||||
---------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new `Indicator` for a mode.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `modeName` => the name of the mode that this `Indicator` is for.
|
||||
]]
|
||||
---------------------------------
|
||||
function Indicator.mode(modeName)
|
||||
return {
|
||||
_ENTRY_MODE_START,
|
||||
Entry.new(_HL_GROUP_PROMPT, tostring(modeName)),
|
||||
_ENTRY_MODE_END
|
||||
}
|
||||
end
|
||||
|
||||
-----------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new `Indicator` for a prompt.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `modeName` => the name of the mode that this `Indicator` is for.
|
||||
]]
|
||||
-----------------------------------
|
||||
function Indicator.prompt(modeName)
|
||||
return '* ' .. tostring(modeName) .. ' > '
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* PUBLICIZE MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
return Indicator
|
@ -1,103 +0,0 @@
|
||||
--[[
|
||||
/*
|
||||
* IMPORTS
|
||||
*/
|
||||
--]]
|
||||
|
||||
local globals = require('libmodal/src/globals')
|
||||
local api = vim.api
|
||||
|
||||
--[[
|
||||
/*
|
||||
* MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
local vars = {}
|
||||
|
||||
vars.libmodalTimeouts = api.nvim_get_var('libmodalTimeouts')
|
||||
|
||||
--[[
|
||||
/*
|
||||
* HELPERS
|
||||
*/
|
||||
--]]
|
||||
|
||||
------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new entry in `vars`
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `keyName` => the name of the key used to refer to this variable in `vars`.
|
||||
* `varName` => the name of the variable as it is stored in vim.
|
||||
]]
|
||||
------------------------------------
|
||||
local function new(keyName)
|
||||
vars[keyName] = {
|
||||
-- Instances of variables pertaining to a certain mode.
|
||||
instances = {},
|
||||
_varName = 'Mode'
|
||||
.. string.upper(string.sub(keyName, 0, 1))
|
||||
.. string.sub(keyName, 2),
|
||||
|
||||
---------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Get the name of `modeName`s global setting.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `modeName` => the name of the mode.
|
||||
]]
|
||||
---------------------------------
|
||||
name = function(__self, modeName)
|
||||
return string.lower(modeName) .. __self._varName
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Retrieve a variable value.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `var` => the `vars.*` table to retrieve the value of.
|
||||
* `modeName` => the mode name this value is being retrieved for.
|
||||
]]
|
||||
------------------------------------
|
||||
function vars.nvim_get(var, modeName)
|
||||
return api.nvim_get_var(var:name(modeName))
|
||||
end
|
||||
|
||||
function vars.nvim_set(var, modeName, val)
|
||||
api.nvim_set_var(var:name(modeName), val)
|
||||
end
|
||||
|
||||
function vars:tearDown(modeName)
|
||||
for _, v in pairs(self) do
|
||||
if type(v) == globals.TYPE_TBL and v.instances[modeName] then
|
||||
v.instances[modeName] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* VARS
|
||||
*/
|
||||
--]]
|
||||
|
||||
new('buffers' )
|
||||
new('combos' )
|
||||
new('completions' )
|
||||
new('exit' )
|
||||
new('help' )
|
||||
new('input' )
|
||||
new('timeouts' )
|
||||
new('timer' )
|
||||
new('windows' )
|
||||
|
||||
--[[
|
||||
/*
|
||||
* PUBLICIZE MODULE
|
||||
*/
|
||||
--]]
|
||||
return vars
|
Loading…
Reference in New Issue