close

DEV Community

Cover image for Neovim toggle moody words
Sérgio Araújo
Sérgio Araújo

Posted on Edited on

Neovim toggle moody words

Toggling values in programming is highlly frequent. What about a lua function and a mapping for that?


local M = {}

M.switch_moody_word = function()
  -- Grupos de estados relacionados (ordem importa)
  local state_groups = {
    { 'true', 'false' },
    { 'on', 'off' },
    { 'in', 'out' },
    { 'start', 'stop' },
    { 'show', 'hide' },
    { 'enable', 'disable' },
    { 'yes', 'no' },
    { 'up', 'down' },
    { 'always', 'never' },
    { 'error', 'warn', 'info', 'debug', 'trace' },
    { 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' },
  }

  -- Ajusta capitalização para combinar com a palavra original
  local function match_case(original, new)
    if original:match('^%u+$') then return new:upper() end -- TODO → DEBUG
    if original:match('^%l+$') then return new:lower() end -- todo → debug
    if original:match('^%u%l+$') then return new:sub(1, 1):upper() .. new:sub(2):lower() end -- Todo → Debug
    return new
  end

  -- Pega a próxima palavra dentro do mesmo grupo
  local function get_next_word(word)
    local lower = word:lower()
    for _, group in ipairs(state_groups) do
      for i, w in ipairs(group) do
        if w == lower then
          local next = group[(i % #group) + 1]
          return match_case(word, next)
        end
      end
    end
    return nil
  end

  -- Palavra sob o cursor
  local word = vim.fn.expand('<cword>')
  local replacement = get_next_word(word)
  if not replacement then return end

  -- Substitui palavra no buffer manualmente (evita bugs com `ciw`)
  local _, col = unpack(vim.api.nvim_win_get_cursor(0))
  local line = vim.api.nvim_get_current_line()

  local start_col = col
  while start_col > 0 and line:sub(start_col, start_col):match('[%w_]') do
    start_col = start_col - 1
  end
  start_col = start_col + 1

  local end_col = col + 1
  while line:sub(end_col, end_col):match('[%w_]') do
    end_col = end_col + 1
  end
  end_col = end_col - 1

  local new_line = line:sub(1, start_col - 1) .. replacement .. line:sub(end_col + 1)
  vim.api.nvim_set_current_line(new_line)
end

return M
Enter fullscreen mode Exit fullscreen mode

Now an intuitive mapping to toggle these words from our list above

local switch_moody_word = require('utils').swich_moody_word

-- NOTE: Adjust the require to fit your environment realitty

vim.keymap.set('n', '<Tab>', function() switch_moody_word() end, {
  desc = ' [T]oggle [b]oolean',
  silent = false,
})
Enter fullscreen mode Exit fullscreen mode

Top comments (0)