aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--toggler.lua95
1 files changed, 95 insertions, 0 deletions
diff --git a/toggler.lua b/toggler.lua
new file mode 100644
index 0000000..4b643af
--- /dev/null
+++ b/toggler.lua
@@ -0,0 +1,95 @@
+-- Author: Georgi Kirilov
+--
+-- You can contact me via email to the posteo.net domain.
+-- The local-part is the Z code for "Place a competent operator on this circuit."
+
+require("vis")
+local vis = vis
+
+local M = {}
+local lookup = {}
+local count
+
+local inner_word = 0
+local char_next = 17
+
+local function toggle(func, motion)
+ return function(file, range, pos)
+ local word = file:content(range)
+ local toggled = func(word, count)
+ if toggled then
+ file:delete(range)
+ file:insert(range.start, toggled)
+ return motion and range.finish or range.start
+ end
+ return pos
+ end
+end
+
+local function make_shift(shift)
+ return function(word, delta)
+ local number = tonumber(word)
+ local iter = number and {number} or lookup[word]
+ if not iter then return end
+ local binary = iter[2] and #iter[2] == 2
+ local neighbor, rotate = shift(iter[1], iter[2], delta)
+ return number and neighbor or iter[2][neighbor] or binary and iter[2][rotate]
+ end
+end
+
+local increment = make_shift(function(i, _, delta) return i + (delta or 1), 1 end)
+local decrement = make_shift(function(i, options, delta) return i - (delta or 1), options and #options end)
+
+local function case(str)
+ return str:gsub("[%l%u]", function(char)
+ local lower = char:lower()
+ return char == lower and char:upper() or lower
+ end)
+end
+
+local function operator_new(key, handler, object, motion, help)
+ local id = vis:operator_register(handler)
+ if id < 0 then
+ return false
+ end
+ local function binding()
+ vis:operator(id)
+ if vis.mode == vis.modes.OPERATOR_PENDING then
+ if object then
+ count = vis.count
+ vis.count = nil
+ vis:textobject(object)
+ elseif motion then
+ vis:motion(motion)
+ end
+ end
+ end
+ vis:map(vis.modes.NORMAL, key, binding, help)
+ vis:map(vis.modes.VISUAL, key, binding, help)
+end
+
+local function preprocess(tbl)
+ local cfg = {}
+ for _, options in ipairs(tbl) do
+ for i, key in ipairs(options) do
+ cfg[key] = {i, options}
+ end
+ end
+ return cfg
+end
+
+vis.events.subscribe(vis.events.INIT, function()
+ operator_new("<C-a>", toggle(increment), inner_word, nil, "Toggle/increment word or selection")
+ operator_new("<C-x>", toggle(decrement), inner_word, nil, "Toggle/decrement word or selection")
+ operator_new("~", toggle(case, true), nil, char_next, "Toggle case of character or selection")
+ operator_new("g~", toggle(case), nil, nil, "Toggle-case operator")
+ operator_new("gu", toggle(string.lower), nil, nil, "Lower-case operator")
+ operator_new("gU", toggle(string.upper), nil, nil, "Upper-case operator")
+ lookup = preprocess(M)
+end)
+
+return function(config)
+ local ext_config = require(config)
+ M = ext_config or M
+ return M
+end