mawkler / modicator.nvim

Cursor line number mode indicator plugin for Neovim
MIT License
298 stars 6 forks source link

How to customize mode colors after recent changes #12

Closed MarcoBuess closed 10 months ago

MarcoBuess commented 1 year ago

Cheers! First of all thanks for taking the time to write this little helper. I'm currently using this ayu-theme with neovim. It features a lualine theme which for some reason diverges in the colors that get picked up by modicator. Up until now I didn't bother much to find out why, as I could easily adjust the colors by mode, to the colors the ayu-theme exposes through its api. With the recent changes, that doesn't seem to be possible anymore. Is there any other API that can be used for customizing mode colors? Here is the lazy.nvim spec I was using to configure modicator as reference.

return {
  "mawkler/modicator.nvim",
  event = "VeryLazy",
  dependencies = "Shatur/neovim-ayu",
  config = function()
    local colors = require("ayu.colors")
    require("modicator").setup({
      show_warnings = false,
      highlights = {
        modes = {
          ["n"] = { foreground = colors.entity },
          ["c"] = { foreground = colors.entity },
          ["v"] = { foreground = colors.accent },
          ["V"] = { foreground = colors.accent },
        },
      },
    })
  end,
}

Any help or pointing towards the right direction is highly appreciated!

mawkler commented 1 year ago

@MarcoBuess Hi! It seems that lualine sets the highlight lualine_a_<mode> for each mode (assuming default lualine configuration). I came up with the following fix for modicator:

local function set_mode_hls_from_lualine()
  local modes = {
    'Normal',
    'Insert',
    'Visual',
    'Command',
    'Replace',
    'Select',
    'Terminal',
    'TerminalNormal',
  }

  for _, mode in pairs(modes) do
    local hl = vim.api.nvim_get_hl(0, { name =  'lualine_a_' .. mode, link = false })
    vim.api.nvim_set_hl(0, mode .. 'Mode', { fg = hl.bg })
  end
end

Try and add this to your modicator config and let me know if this also works for you!

I thought about natively supporting lualine from modicator, but I'm not sure of how to get the prefix of the mode highlight (lualine_a_) more generically if the user has their mode in another section than a.

MarcoBuess commented 1 year ago

@mawkler Thanks for the quick reply. I tried your suggestion, adjusting my lazy spec like so:

return {
  "mawkler/modicator.nvim",
  event = "VeryLazy",
  dependencies = "Shatur/neovim-ayu",
  config = function()
    local function set_mode_hls_from_lualine()
      local modes = {
        "Normal",
        "Insert",
        "Visual",
        "Command",
        "Replace",
        "Select",
        "Terminal",
        "TerminalNormal",
      }

      for _, mode in pairs(modes) do
        local hl = vim.api.nvim_get_hl(0, { name = "lualine_a_" .. mode, link = false })
        vim.api.nvim_set_hl(0, mode .. "Mode", { fg = hl.bg })
      end
    end

    set_mode_hls_from_lualine()

    require("modicator").setup({
      show_warnings = false,
    })
  end,
}

I noticed two things:

  1. Its not working consistently when restarting nvim
  2. COMMAND mode color still differs from what lualine is showing

Aside of that it seems to be working! Could 1. be related to lualine needing to be loaded before modicator?

I thought about natively supporting lualine from modicator, but I'm not sure of how to get the prefix of the mode highlight (lualinea) more generically if the user has their mode in another section than a.

I looked up the lualine docs and found require("lualine").get_confg() which will query the config. One could get the sections like so: require("lualine").get_config().sections

A smart person (not me) could surely figure out how to walk over that, maybe using recursion to find the section that has the mode configured.

mawkler commented 1 year ago

@MarcoBuess

Its not working consistently when restarting nvim

This is because ayu's CursorLineNr highlight isn't the same as lualine's normal mode highlight. I added a fix for this in #16 that ensures that the normal mode highlight is set correctly on load.

COMMAND mode color still differs from what lualine is showing

I couldn't reproduce this. I tried it with Shatur/neovim-ayu but it seems to have the same blue lualine highlight for both normal and command mode, which modicator uses correctly.

MarcoBuess commented 1 year ago

I tried it with Shatur/neovim-ayu but it seems to have the same blue lualine highlight for both normal and command mode, which modicator uses correctly.

For some strange reason cursorline is purple for me in command mode.

MarcoBuess commented 1 year ago

@mawkler I came up with a potential solution for

I thought about natively supporting lualine from modicator, but I'm not sure of how to get the prefix of the mode highlight (lualinea) more generically if the user has their mode in another section than a.

I don't really have a clue about lua by any means, but I got something working with a little experimenting and borrowing from stackoverflow:

local ok, lualine = pcall(require, "lualine")
if not ok then
    vim.print("Required module lualine could not be loaded.")
end

local function find_lualine_mode(sections)
    local function hasValue(tbl, value)
        for _, v in ipairs(tbl) do
            if v == value or (type(v) == "table" and hasValue(v, value)) then
                return true
            end
        end
        return false
    end

    for k, v in pairs(sections) do
        if hasValue(v, "mode") then
            vim.print("Found mode in", k)
        end
    end
end

find_lualine_mode(lualine.get_config().sections)

Maybe this helps you solve the "problem".

MarcoBuess commented 1 year ago

@mawkler As this didn't let me sleep. I came up with this rather ugly spec attempt:

return {
  "mawkler/modicator.nvim",
  event = "VeryLazy",
  dependencies = "Shatur/neovim-ayu",
  config = function()
    local function set_mode_hls_from_lualine()
      local ok, lualine = pcall(require, "lualine")
      if not ok then
        vim.print("Required module lualine could not be loaded.")
      end

      local function find_lualine_mode(sections)
        local function hasValue(tbl, value)
          for _, v in ipairs(tbl) do
            if v == value or (type(v) == "table" and hasValue(v, value)) then
              return true
            end
          end
          return false
        end

        for k, v in pairs(sections) do
          if hasValue(v, "mode") then
            return k
          end
        end
      end

      local mode_section = find_lualine_mode(lualine.get_config().sections)

      for k, v in pairs(vim.api.nvim_get_hl(0, { link = false })) do
        -- getmetatable() to filter out vim.empty_dict()
        if string.match(k, string.format("^%s_%%a+$", mode_section)) and getmetatable(v) == nil then
          local mode, _ = string.sub(k, 11):gsub("^%l", string.upper)
          vim.api.nvim_set_hl(0, mode .. "Mode", { fg = v.bg })
        end
      end
    end

    set_mode_hls_from_lualine()
  end,
  opts = {
    show_warnings = false,
  },
}

Which, at least in my understanding should do what its supposed to, but doesn't seem to set the hl. Can you tell what I'm missing?

MarcoBuess commented 1 year ago

@mawkler I made it work. Here is the lazyvim spec:

return {
  "mawkler/modicator.nvim",
  event = "VeryLazy",
  dependencies = "Shatur/neovim-ayu",
  config = function()
    local function has_value(tbl, value)
      for _, v in ipairs(tbl) do
        if v == value or (type(v) == "table" and has_value(v, value)) then
          return true
        end
      end
      return false
    end

    local function find_mode_section(config_sections)
      for k, section in pairs(config_sections) do
        if has_value(section, "mode") then
          return k
        end
      end
    end

    local function set_mode_hl_from_lualine()
      local ok, lualine = pcall(require, "lualine")
      assert(ok, "Failed to load lualine module")

      local mode_section = find_mode_section(lualine.get_config().sections)
      assert(mode_section, "Could not find mode section in lualine config")

      for hl_group, hl_def in pairs(vim.api.nvim_get_hl(0, { link = false })) do
        local mode_key_pattern = string.format("^%s_%%a+$", mode_section)
        -- getmetatable() as I didn't come up with a better solution to filter out vim.empty_dict()
        if string.match(hl_group, mode_key_pattern) and not getmetatable(hl_def) then
          local mode = hl_group:sub(11):gsub("^%l", string.upper) .. "Mode"
          vim.api.nvim_set_hl(0, mode, { fg = hl_def.bg })
        end
      end
    end

    set_mode_hl_from_lualine()

    require("modicator").setup({
      show_warnings = false,
    })
  end,
}

I made it as concise and hopefully clear as I could. The key here was to call require("modicator").setup({...}) after setting the highlight, as it wouldn't pick it up otherwise. Feedback highly welcome ❤️

mawkler commented 1 year ago

@MarcoBuess Thank you for this! When I find the time I'll try and add this natively to modicator 🙂

MarcoBuess commented 10 months ago

Yay! I guess that means I can replace my filthy hack with

integration = { 
    lualine = {
         enabled = true,
    }, 
},

Right?

MarcoBuess commented 10 months ago

Just tried it out. Works with a simplistic spec as

    {
        "mawkler/modicator.nvim",
        event = "VeryLazy",
        dependencies = "Shatur/neovim-ayu",
        opts = {
            show_warnings = false,
        },
    }

as clean as it gets. love it ❤️