-- 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, novisual) 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) if not novisual then vis:map(vis.modes.VISUAL, key, binding, help) end 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("", toggle(increment), inner_word, nil, "Toggle/increment word or selection", true) operator_new("", toggle(decrement), inner_word, nil, "Toggle/decrement word or selection", true) 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) vis:map(vis.modes.NORMAL, "g~~", "g~il") vis:map(vis.modes.NORMAL, "guu", "guil") vis:map(vis.modes.NORMAL, "gUU", "gUil") vis:map(vis.modes.VISUAL, "u", "gu") vis:map(vis.modes.VISUAL, "U", "gU") end) return function(config) local ext_config = require(config) M = ext_config or M return M end