fix(mode): incompatible with vim.v.count (#26)
* fix(mode): incompatible with vim.v.count * ref(Vars): track local copy of global value * ref(Mode): use new `Vars` * ref(Mode): handle exit during `enter` * ref: swap `Var.new` param order Mode name should come before var name * docs(examples): Vars * ref: rename `Vars` -> `Var` * fix(Mode): check if `exit == 1` for vim compat * fix(Prompt): use new `Var` impl * ref: remove `count1` It seems like `math.max` is enough for this purpose * doc: use h3 headerspull/32/head
parent
1ecc4add3b
commit
485b77bf14
@ -0,0 +1,79 @@
|
||||
--[[
|
||||
This file demonstrates how `Var`s work in Modes and Prompts.
|
||||
]]
|
||||
|
||||
--- WARN: do not import this in your code! it is not part of the public API.
|
||||
local Var = require 'libmodal.utils.Var'
|
||||
|
||||
--- Check the value of the local var
|
||||
--- @param var any
|
||||
--- @param val unknown the value to check is equal to
|
||||
local function assert_local_eq(var, val)
|
||||
assert(var:get_local() == val, 'assertion: the global value equals ' .. vim.inspect(val))
|
||||
end
|
||||
|
||||
--- Check the value of the global var
|
||||
--- @param var any
|
||||
--- @param val unknown the value to check is equal to
|
||||
local function assert_global_eq(var, val)
|
||||
assert(var:get_global() == val, 'assertion: the global value equals ' .. vim.inspect(val))
|
||||
end
|
||||
|
||||
--- Check the value of the scoped var
|
||||
--- @param var any
|
||||
--- @param val unknown the value to check is equal to
|
||||
--- @param scope 'global'|'local'
|
||||
local function assert_eq(var, val, scope)
|
||||
assert(var:get() == val, 'assertion: the value equals ' .. vim.inspect(val))
|
||||
local fn = scope == 'local' and assert_local_eq or assert_global_eq
|
||||
fn(var, val)
|
||||
end
|
||||
|
||||
--- check the value of all vars
|
||||
--- @param var any
|
||||
--- @param val unknown the value to check is equal to
|
||||
local function assert_all_eq(var, val)
|
||||
assert_eq(var, val, 'local')
|
||||
assert_global_eq(var, val)
|
||||
end
|
||||
|
||||
local mode_name = 'Foo'
|
||||
local var_name = 'Bar'
|
||||
|
||||
--- WARN: do not use this function in your code! It is not part of the public API.
|
||||
local foo = Var.new(mode_name, var_name)
|
||||
|
||||
-- 1. baseline
|
||||
|
||||
assert_all_eq(foo, nil)
|
||||
|
||||
-- 2. without local value, `:get` and `:set` use globals
|
||||
|
||||
local global_value = true
|
||||
|
||||
foo:set(global_value)
|
||||
|
||||
assert_eq(foo, global_value, 'global')
|
||||
assert_local_eq(foo, nil)
|
||||
|
||||
-- 3. set local value
|
||||
|
||||
foo:set_local(global_value)
|
||||
|
||||
assert_all_eq(foo, global_value)
|
||||
|
||||
-- 4. with local value, `:get` and `:set` use locals
|
||||
|
||||
local local_value = false
|
||||
|
||||
foo:set(local_value)
|
||||
|
||||
assert_eq(foo, local_value, 'local')
|
||||
assert_global_eq(foo, global_value)
|
||||
|
||||
-- Finally, unset all so the test can be run again
|
||||
|
||||
foo:set_global(nil)
|
||||
foo:set_local(nil)
|
||||
|
||||
assert_all_eq(foo, nil)
|
@ -0,0 +1,103 @@
|
||||
--- @param str_with_spaces string
|
||||
--- @param first_letter_modifier fun(s: string): string
|
||||
local function no_spaces(str_with_spaces, first_letter_modifier)
|
||||
local split_str = vim.split(str_with_spaces:gsub(vim.pesc '_', vim.pesc ' '), ' ')
|
||||
|
||||
--- @param str string
|
||||
--- @param func fun(s: string): string
|
||||
local function camel_case(str, func)
|
||||
return func(str:sub(0, 1) or '') .. (str:sub(2) or ''):lower()
|
||||
end
|
||||
|
||||
split_str[1] = camel_case(split_str[1], first_letter_modifier)
|
||||
|
||||
for i = 2, #split_str do split_str[i] =
|
||||
camel_case(split_str[i], string.upper)
|
||||
end
|
||||
|
||||
return table.concat(split_str)
|
||||
end
|
||||
|
||||
--- @class libmodal.utils.Var
|
||||
--- @field private mode_name string the highlight group to use when printing `str`
|
||||
--- @field private value? unknown the local value of the variable
|
||||
--- @field private var_name string the highlight group to use when printing `str`
|
||||
local Var = require('libmodal.utils.classes').new()
|
||||
|
||||
--- create a new set of variables
|
||||
--- @param mode_name string the name of the mode
|
||||
--- @param var_name string the name of the key used to refer to this variable in `Var`.
|
||||
--- @param default_global? unknown the default global value
|
||||
--- @return libmodal.utils.Var
|
||||
function Var.new(mode_name, var_name, default_global)
|
||||
local self = setmetatable({}, Var)
|
||||
|
||||
self.mode_name = no_spaces(mode_name, string.lower)
|
||||
self.var_name = 'Mode' .. no_spaces(var_name, string.upper)
|
||||
self.value = nil
|
||||
|
||||
if default_global ~= nil and self:get_global() == nil then
|
||||
self:set_global(default_global)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @generic T
|
||||
--- @return T value the local value if it exists, or the global value
|
||||
function Var:get()
|
||||
local local_value = self:get_local()
|
||||
if local_value == nil then
|
||||
return self:get_global()
|
||||
end
|
||||
|
||||
return local_value
|
||||
end
|
||||
|
||||
--- @generic T
|
||||
--- @return T global_value the global value
|
||||
function Var:get_local()
|
||||
return self.value
|
||||
end
|
||||
|
||||
--- @generic T
|
||||
--- @return T global_value the global value
|
||||
function Var:get_global()
|
||||
return vim.g[self:name()]
|
||||
end
|
||||
|
||||
--- @return string name the global Neovim setting
|
||||
function Var:name()
|
||||
return self.mode_name .. self.var_name
|
||||
end
|
||||
|
||||
--- NOTE: the local value is only set if not `nil`, for backwards compatibility purposes.
|
||||
--- local values did not always exist, and since `get` prefers local values, it may
|
||||
--- too-eagerly shadow the global variable.
|
||||
--- @param val unknown set local value if it exists, or the global value
|
||||
--- @return nil
|
||||
function Var:set(val)
|
||||
if self:get_local() == nil then
|
||||
self:set_global(val)
|
||||
else
|
||||
self:set_local(val)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param val unknown set the local value equal to this
|
||||
--- @return nil
|
||||
function Var:set_local(val)
|
||||
self.value = val
|
||||
end
|
||||
|
||||
--- @param val unknown set the global value equal to this
|
||||
--- @return nil
|
||||
function Var:set_global(val)
|
||||
if val == nil then
|
||||
vim.api.nvim_del_var(self:name()) -- because `nvim_set_var('foo', nil)` actually sets 'foo' to `vim.NIL`
|
||||
else
|
||||
vim.api.nvim_set_var(self:name(), val)
|
||||
end
|
||||
end
|
||||
|
||||
return Var
|
@ -1,56 +0,0 @@
|
||||
--- @class libmodal.utils.Vars
|
||||
--- @field private mode_name string the highlight group to use when printing `str`
|
||||
--- @field private var_name string the highlight group to use when printing `str`
|
||||
local Vars = require('libmodal.utils.classes').new()
|
||||
|
||||
--- @return unknown `vim.g[self:name()])`
|
||||
function Vars:get()
|
||||
return vim.g[self:name()]
|
||||
end
|
||||
|
||||
--- @return string name the global Neovim setting
|
||||
function Vars:name()
|
||||
return self.mode_name .. self.var_name
|
||||
end
|
||||
|
||||
--- create a new set of variables
|
||||
--- @param var_name string the name of the key used to refer to this variable in `Vars`.
|
||||
--- @param mode_name string the name of the mode
|
||||
--- @return libmodal.utils.Vars
|
||||
function Vars.new(var_name, mode_name)
|
||||
local self = setmetatable({}, Vars)
|
||||
|
||||
--- @param str_with_spaces string
|
||||
--- @param first_letter_modifier fun(s: string): string
|
||||
local function no_spaces(str_with_spaces, first_letter_modifier)
|
||||
local split_str = vim.split(str_with_spaces:gsub(vim.pesc '_', vim.pesc ' '), ' ')
|
||||
|
||||
--- @param str string
|
||||
--- @param func fun(s: string): string
|
||||
local function camel_case(str, func)
|
||||
return func(str:sub(0, 1) or '') .. (str:sub(2) or ''):lower()
|
||||
end
|
||||
|
||||
split_str[1] = camel_case(split_str[1], first_letter_modifier)
|
||||
|
||||
for i = 2, #split_str do split_str[i] =
|
||||
camel_case(split_str[i], string.upper)
|
||||
end
|
||||
|
||||
return table.concat(split_str)
|
||||
end
|
||||
|
||||
self.mode_name = no_spaces(mode_name, string.lower)
|
||||
self.var_name = 'Mode' .. no_spaces(var_name, string.upper)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @generic T
|
||||
--- @param val T set `g:{self:name()})` equal to this value
|
||||
--- @return nil
|
||||
function Vars:set(val)
|
||||
vim.api.nvim_set_var(self:name(), val)
|
||||
end
|
||||
|
||||
return Vars
|
Loading…
Reference in New Issue