VERSION = "0.1.0" PLUGIN_NAME = "case" local micro = import("micro") local config = import("micro/config") local util = import("micro/util") local buffer = import("micro/buffer") function init () config.MakeCommand(PLUGIN_NAME .. ".upper", caseUpper, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".lower", caseLower, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".snake", caseSnake, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".kebab", caseKebab, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".uppersnake", caseUpperSnake, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".upperkebab", caseUpperKebab, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".camel", caseCamel, config.NoComplete) config.MakeCommand(PLUGIN_NAME .. ".pascal", casePascal, config.NoComplete) end function caseUpper (bufferPane) case(bufferPane, "upper") end function caseLower (bufferPane) case(bufferPane, "lower") end function caseSnake (bufferPane) case(bufferPane, "snake") end function caseKebab (bufferPane) case(bufferPane, "kebab") end function caseUpperSnake (bufferPane) case(bufferPane, "uppersnake") end function caseUpperKebab (bufferPane) case(bufferPane, "upperkebab") end function caseCamel (bufferPane) case(bufferPane, "camel") end function casePascal (bufferPane) case(bufferPane, "pascal") end function case (bufferPane, cas) local cursor = bufferPane.Buf:GetActiveCursor() if not (cursor and cursor:HasSelection()) then return end local sstart, send = nil, nil if cursor.CurSelection[1]:GreaterThan(-cursor.CurSelection[2]) then sstart, send = cursor.CurSelection[2], cursor.CurSelection[1] else sstart, send = cursor.CurSelection[1], cursor.CurSelection[2] end sstart = buffer.Loc(sstart.X, sstart.Y) send = buffer.Loc(send.X, send.Y) local selection = util.String(cursor:GetSelection()) selection = changeCase(selection, cas) bufferPane.Buf:Replace(sstart, send, selection) end function changeCase (text, cas) if cas == "upper" then return string.upper(text) elseif cas == "lower" then return string.lower(text) elseif cas == "snake" then return concatTokens(lowerCaseTokens(tokenize(text)), "_") elseif cas == "kebab" then return concatTokens(lowerCaseTokens(tokenize(text)), "-") elseif cas == "uppersnake" then return concatTokens(upperCaseTokens(tokenize(text)), "_") elseif cas == "upperkebab" then return concatTokens(upperCaseTokens(tokenize(text)), "-") elseif cas == "camel" then return concatTokens(camelCaseTokens(tokenize(text)), "") elseif cas == "pascal" then return concatTokens(pascalCaseTokens(tokenize(text)), "") end end function tokenize (text) local tokens = { } local wasAlphanumeric = false local newToken = function () if #tokens == 0 or tokens[#tokens].text ~= "" then table.insert(tokens, { text = "" }) end tokens[#tokens].word = true end for index = 1, #text do local ch = text:sub(index, index) local alphanumeric = ch:match("%w") ~= nil local uppercase = ch:match("%u") ~= nil if uppercase or alphanumeric ~= wasAlphanumeric then newToken() end if ch ~= " " and ch ~= "-" and ch ~= "_" then tokens[#tokens].text = tokens[#tokens].text .. ch end if not alphanumeric then tokens[#tokens].word = false end wasAlphanumeric = alphanumeric end return tokens end function mapOverTokens (tokens, callback) local result = { } for index, token in ipairs(tokens) do token = { text = token.text, word = token.word, } callback(index, token) result[index] = token end return result end function lowerCaseTokens (tokens) return mapOverTokens(tokens, function (index, token) if token.word then token.text = string.lower(token.text) end end) end function upperCaseTokens (tokens) return mapOverTokens(tokens, function (index, token) if token.word then token.text = string.upper(token.text) end end) end function camelCaseTokens (tokens) local wasAlphanumeric = false return mapOverTokens(tokens, function (index, token) if token.word and wasAlphanumeric then token.text = (token.text:gsub("^%l", string.upper)) end wasAlphanumeric = token.word end) end function pascalCaseTokens (tokens) return mapOverTokens(tokens, function (index, token) if token.word then token.text = (token.text:gsub("^%l", string.upper)) end end) end function concatTokens (tokens, separator) local result = "" local wasAlphanumeric = false for index, token in ipairs(tokens) do if wasAlphanumeric and token.word then result = result .. separator end wasAlphanumeric = token.word result = result .. token.text end return result end