From f70704ea6a05ce579820ff6f57cfe64c69d29168 Mon Sep 17 00:00:00 2001 From: Iron-E Date: Sun, 3 May 2020 16:38:04 -0400 Subject: [PATCH] Improve ParseTable; continue mode.enter --- lua/libmodal/src/mode/ParseTable/init.lua | 116 ++++++++++----------- lua/libmodal/src/mode/init.lua | 39 ++++++- lua/libmodal/src/utils/Indicator/Entry.lua | 5 +- lua/libmodal/src/utils/api.lua | 59 ++++++++++- 4 files changed, 154 insertions(+), 65 deletions(-) diff --git a/lua/libmodal/src/mode/ParseTable/init.lua b/lua/libmodal/src/mode/ParseTable/init.lua index ae062c9..51f6ffd 100644 --- a/lua/libmodal/src/mode/ParseTable/init.lua +++ b/lua/libmodal/src/mode/ParseTable/init.lua @@ -21,7 +21,8 @@ local strings = {} -- not to be returned. */ --]] -ParseTable.EXE = 'exe' +-- The number corresponding to in vim. +ParseTable.CR = 13 --[[ /* @@ -34,7 +35,7 @@ function strings.split(str, pattern) for char in string.gmatch(str, pattern) do table.insert(split, char) end - return table.concat(split, '') + return split end ------------------------- @@ -46,69 +47,68 @@ end ]] ------------------------- function ParseTable:new(userTable) - local userTable = { - ------------------------------- - --[[ SUMMARY: - * Put `value` into the parse tree as `key`. - ]] - --[[ PARAMS: - * `key` => the key that `value` is reffered to by. - * `value` => the value to store as `key`. - ]] - ------------------------------- - _put = function(__self, key, value) - -- Iterate to get the next dictionaries. - local function _access(dict, splitKey) - -- Get the next character in the table. - local char = api.nvim_eval('char2nr(' .. table.remove(splitKey) .. ')') - - -- If there are still items in the table. - if #splitKey > 0 then - if not dict[char] then - dict[char] = {} - -- If there is a previous command mapping in place - elseif type(dict[char]) == 'string' then - -- Swap the mapping to an s:EX_KEY. - dict[char] = {[ParseTable.EXE] = dict[char]} - end - - dict[char] = _access(dict, key) - elseif dict[key] then - dict[key][char] = value - else - dict[key] = value + local parseTable = {} + + ------------------------------- + --[[ SUMMARY: + * Put `value` into the parse tree as `key`. + ]] + --[[ PARAMS: + * `key` => the key that `value` is reffered to by. + * `value` => the value to store as `key`. + ]] + ------------------------------- + function parseTable:parsePut(key, value) + -- Internal recursion function. + local function update(dict, splitKey) -- † + -- Get the next character in the table. + local k = api.nvim_eval("char2nr('" .. table.remove(splitKey) .. "')") + + -- If there are still kacters left in the key. + if #splitKey > 0 then + if not dict[k] then + dict[k] = {} + -- If there is a previous command mapping in place + elseif type(dict[k]) == 'string' then + -- Swap the mapping to a `CR` + dict[k] = {[ParseTable.CR] = dict[k]} end - return dict + -- run update() again + update(dict[k], splitKey) + -- If dict[k] is a pre-existing table, don't clobber the table— clobber the `CR` value. + elseif type(dict[k]) == 'table' then + dict[k][ParseTable.CR] = value + -- If dict[k] is not a table, go ahead and clobber the value. + else + dict[k] = value end + end -- ‡ - -- Iterate over ther eturn from access. - for k, v in pairs(_access( - __self, strings.split(string.reverse(key), '.') - )) do - table.insert(parsedDict, k, v) - end - end, + -- Run the recursive function. + update(self, strings.split( + string.reverse(key), '.' + )) + end - ------------------------------- - --[[ SUMMARY: - * Create the union of `self` and `tableToUnite` - ]] - --[[ PARAMS: - * `tableToUnite` => the table to unite with `self.` - ]] - ------------------------------- - union = function(__self, tableToUnite) - for k, v in pairs(tableToUnite) do - if not __self[k] then - __self:_put(k, v) - end - end + ------------------------------- + --[[ SUMMARY: + * Create the union of `self` and `tableToUnite` + ]] + --[[ PARAMS: + * `tableToUnite` => the table to unite with `self.` + ]] + ------------------------------- + function parseTable:parsePutAll(tableToUnite) + for k, v in pairs(tableToUnite) do + self:parsePut(k, v) end - } - + end - return userTable:_union(userTable) + -- Parse the passed in table. + parseTable:parsePutAll(userTable) + -- Return the new `ParseTable`. + return parseTable end --[[ diff --git a/lua/libmodal/src/mode/init.lua b/lua/libmodal/src/mode/init.lua index 53e7507..1473bad 100644 --- a/lua/libmodal/src/mode/init.lua +++ b/lua/libmodal/src/mode/init.lua @@ -5,7 +5,6 @@ --]] local globals = require('libmodal/src/base/globals') -local ParseTable = require('libmodal/src/mode/ParseTable') local utils = require('libmodal/src/utils') local api = utils.api @@ -18,6 +17,7 @@ local vars = utils.vars --]] local mode = {} +mode.ParseTable = require('libmodal/src/mode/ParseTable') ------------------------ --[[ SUMMARY: @@ -33,7 +33,7 @@ local mode = {} function mode.enter(...) local args = {...} - --[[ VAR INIT ]] + --[[ SETUP. ]] -- Create the indicator for the mode. local indicator = utils.Indicator:new(args[1]) @@ -56,12 +56,42 @@ function mode.enter(...) else doTimeout = vars.libmodalTimeout end + vars.timeout.instances[modeName] = doTimeout + -- Build the parse tree. + vars.combos.instances[modeName] = mode.ParseTable:new(args[2]) - vars.timeout.instances[modeName] = doTimeout + -- Initialize the input history variable. + vars.input.instances[modeName] = {} + end + + --[[ MODE LOOP. ]] - vars.combos.instances[modeName] = ParseTable:new(a[2]) + while true do + -- Try (using pcall) to use the mode. + local noErrors = pcall(function() + -- TODO: write main loop. + end)() + + -- If there were errors, handle them. + if not noErrors then + api.nvim_bell() + api.nvim_show_err( 'vim-libmodal error', + api.nvim_get_vvar('throwpoint') + .. '\n' .. + api.nvim_get_vvar('exception') + ) + break + end end + + --[[ TEARDOWN. ]] + + --[[ TODO: translate these: + call s:Restore(l:winState) + mode | echo '' + call garbagecollect() + ]] end --[[ @@ -70,6 +100,5 @@ end */ --]] mode.enter('test', {}) -print(tostring(string.gmatch('testing', '.'))) return mode diff --git a/lua/libmodal/src/utils/Indicator/Entry.lua b/lua/libmodal/src/utils/Indicator/Entry.lua index cf11d9c..629077d 100644 --- a/lua/libmodal/src/utils/Indicator/Entry.lua +++ b/lua/libmodal/src/utils/Indicator/Entry.lua @@ -22,7 +22,10 @@ local Entry = {} ]] -------------------------------------------------------- function Entry.new(hlgroup, str) - return {hlgroup, str} + return { + ['hl'] = hlgroup, + ['str'] = str + } end --[[ diff --git a/lua/libmodal/src/utils/api.lua b/lua/libmodal/src/utils/api.lua index becb15f..068542e 100644 --- a/lua/libmodal/src/utils/api.lua +++ b/lua/libmodal/src/utils/api.lua @@ -5,6 +5,7 @@ --]] local globals = require('libmodal/src/base/globals') +local Entry = require('libmodal/src/utils/Indicator/Entry.lua') --[[ /* @@ -14,11 +15,20 @@ local globals = require('libmodal/src/base/globals') local api = vim.api +------------------------ +--[[ SUMMARY: + * Make vim ring the visual/audio bell, if it is enabled. +]] +------------------------ +function api.nvim_bell() + local escape = api.nvim_eval("nr2char('" .. 27 .. "')") + api.nvim_command('normal ' .. escape) +end + ----------------------------------- --[[ SUMMARY: * Check whether or not some variable exists. ]] - --[[ * `scope` => The scope of the variable (i.e. `g`, `l`, etc.) * `var` => the variable to check for. @@ -28,6 +38,53 @@ function api.nvim_exists(scope, var) return api.nvim_eval("exists('" .. scope .. ":" .. var .. "')") ~= globals.VIM_FALSE end +------------------------ +--[[ SUMMARY: + * Echo a table of {`hlgroup`, `str`} tables. + * Meant to be read as "nvim list echo". +]] +--[[ PARAMS: + * `hlTables` => the tables to echo with highlights. +]] +------------------------ +function api.nvim_lecho(hlTables) + api.nvim_redraw() + for _, hlTable in ipairs(hlTables) do + api.nvim_command( + -- `:echohl` the hlgroup and then `:echon` the string. + "execute(['echohl " .. hlTable.hl .. "', 'echon " .. hlTable.str .. "'])" + ) + end + api.nvim_command('echohl None') +end + +-------------------------- +--[[ SUMMARY: + * Run `mode` to refresh the screen. + * The function was not named `nvim_mode` because that would be really confusing given the name of this plugin. +]] +-------------------------- +function api.nvim_redraw() + api.nvim_command('mode') +end + +------------------------------- +--[[ SUMMARY: + * Show a `title` error. +]] +--[[ PARAMS: + * `title` => the title of the error. + * `msg` => the message of the error. +]] +------------------------------- +function api.nvim_show_err(title, msg) + api.nvim_lecho({ + Entry.new('Title', title .. '\n'), + Entry.new('Error', msg), + Entry.new('Question', '\n[Press any key to return]') + }) +end + --[[ /* * PUBLICIZE MODULE