Created
April 22, 2026 17:42
-
-
Save eduardoarandah/0820b469b2921461558862730578a393 to your computer and use it in GitHub Desktop.
Revisions
-
eduardoarandah created this gist
Apr 22, 2026 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,169 @@ ---------------------------------------------------- -- text-case -- https://github.com/johmsalas/text-case.nvim#setup ---------------------------------------------------- vim.pack.add({ "https://github.com/johmsalas/text-case.nvim", }) local textcase = require("textcase") textcase.setup({ default_keymappings_enabled = false, }) -- Load extension only if telescope is available local ok, telescope = pcall(require, "telescope") if ok then telescope.load_extension("textcase") end -- ════════════════════════════════════════════════════════════ -- Central cases table: single source of truth -- ════════════════════════════════════════════════════════════ local cases = { { method = "to_upper_case", label = "Upper", example = "LOREM IPSUM", word = "u", lsp = "U", op = "u" }, { method = "to_lower_case", label = "Lower", example = "lorem ipsum", word = "l", lsp = "L", op = "l" }, { method = "to_snake_case", label = "Snake", example = "lorem_ipsum", word = "s", lsp = "S", op = "s" }, { method = "to_dash_case", label = "Dash/Kebab", example = "lorem-ipsum", word = "d", lsp = "D", op = "d" }, { method = "to_title_dash_case", label = "Title-Dash", example = "Lorem-Ipsum", word = "k", lsp = "K", op = "k" }, { method = "to_constant_case", label = "Constant", example = "LOREM_IPSUM", word = "n", lsp = "N", op = "n" }, { method = "to_dot_case", label = "Dot", example = "lorem.ipsum", word = "o", lsp = "O", op = "o" }, { method = "to_comma_case", label = "Comma", example = "lorem,ipsum", word = ",", lsp = "<", op = "," }, { method = "to_camel_case", label = "Camel", example = "loremIpsum", word = "c", lsp = "C", op = "c" }, { method = "to_pascal_case", label = "Pascal", example = "LoremIpsum", word = "p", lsp = "P", op = "p" }, { method = "to_title_case", label = "Title", example = "Lorem Ipsum", word = "t", lsp = "T", op = "t" }, { method = "to_path_case", label = "Path", example = "lorem/ipsum", word = "f", lsp = "F", op = "f" }, { method = "to_phrase_case", label = "Phrase", example = "Lorem ipsum", word = "a", lsp = "A", op = "a" }, } -- ════════════════════════════════════════════════════════════ -- Keymap registration -- ════════════════════════════════════════════════════════════ -- Prefixes: -- ga<key> → current_word (changes the word under the cursor) -- ga<KEY> → lsp_rename (rename via LSP, uppercase letter) -- ge<key> → operator (awaits motion: gesw, gesiw, etc.) local map = vim.keymap.set for _, c in ipairs(cases) do map("n", "ga" .. c.word, function() textcase.current_word(c.method) end, { desc = "TextCase: " .. c.label .. " (word)" }) map("n", "ga" .. c.lsp, function() textcase.lsp_rename(c.method) end, { desc = "TextCase: " .. c.label .. " (LSP rename)" }) map("n", "ge" .. c.op, function() textcase.operator(c.method) end, { desc = "TextCase: " .. c.label .. " (operator)" }) end -- ════════════════════════════════════════════════════════════ -- Helpers for :TextCaseReplace and :TextCaseLspRename -- ════════════════════════════════════════════════════════════ local function pick_case(prompt, on_choice) vim.ui.select(cases, { prompt = prompt, format_item = function(c) return string.format("%-14s %s", c.label, c.example) end, }, function(choice) if choice then on_choice(choice) end end) end -- ════════════════════════════════════════════════════════════ -- :Case → case selector -- - In normal mode: acts on the word under the cursor -- - In visual mode: acts on the selection (:'<,'>TextCaseReplace) -- ════════════════════════════════════════════════════════════ vim.api.nvim_create_user_command("Case", function(opts) local is_visual = opts.range > 0 pick_case("Convert to:", function(choice) if is_visual then -- Reapply the last visual selection and call the operator -- Why gv instead of marks '< / '>? -- When you execute :TextCaseReplace from visual mode, Neovim exits visual mode before running the command -- marks '< and '> are set but the mode is already normal. -- gv reactivates the last visual selection (with the same type: charwise, linewise or blockwise), -- which is exactly what textcase.operator() expects to detect the range. vim.cmd("normal! gv") textcase.operator(choice.method) else textcase.current_word(choice.method) end end) end, { desc = "Select case and replace word/selection", range = true, }) -- :TextCaseLspRename → case selector via LSP rename vim.api.nvim_create_user_command("CaseLSP", function() pick_case("LSP rename to:", function(choice) textcase.lsp_rename(choice.method) end) end, { desc = "Select case and LSP rename symbol under cursor" }) -- ════════════════════════════════════════════════════════════ -- :CaseHelp → shows the table in a floating popup -- ════════════════════════════════════════════════════════════ local function show_mappings_popup() local lines = { " Change case", " ─────────────────", "", string.format(" %-14s %-18s %-8s %-8s %-8s", "Case", "Example", "Word", "LSP", "Operator"), string.format(" %-14s %-18s %-8s %-8s %-8s", string.rep("─", 14), string.rep("─", 18), string.rep("─", 8), string.rep("─", 8), string.rep("─", 8)), } for _, c in ipairs(cases) do table.insert(lines, string.format(" %-14s %-18s ga%-6s ga%-6s ge%-6s", c.label, c.example, c.word, c.lsp, c.op)) end table.insert(lines, "") table.insert(lines, " Prefix: ga<k>=word ga<K>=LSP ge<k>=operator (motion)") table.insert(lines, " Press q or <Esc> to close") -- Calculate dimensions local width = 0 for _, l in ipairs(lines) do width = math.max(width, vim.fn.strdisplaywidth(l)) end width = width + 2 local height = #lines local buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) vim.bo[buf].modifiable = false vim.bo[buf].bufhidden = "wipe" vim.bo[buf].filetype = "textcase_help" local win = vim.api.nvim_open_win(buf, true, { relative = "editor", width = width, height = height, row = math.floor((vim.o.lines - height) / 2), col = math.floor((vim.o.columns - width) / 2), style = "minimal", border = "rounded", title = " TextCase ", title_pos = "center", }) vim.wo[win].cursorline = true -- Close with q or <Esc> local close = function() pcall(vim.api.nvim_win_close, win, true) end vim.keymap.set("n", "q", close, { buffer = buf, nowait = true, silent = true }) vim.keymap.set("n", "<Esc>", close, { buffer = buf, nowait = true, silent = true }) end vim.api.nvim_create_user_command("CaseHelp", show_mappings_popup, { desc = "Show TextCase help" })