luckasRanarison / tailwind-tools.nvim

An unofficial Tailwind CSS integration and tooling for Neovim
https://dotfyle.com/plugins/luckasRanarison/tailwind-tools.nvim
MIT License
394 stars 17 forks source link

How to support CVA? #58

Closed nicksrandall closed 4 days ago

nicksrandall commented 1 month ago

Related to #26, I'd like to understand how to use (CVA)[https://cva.style/docs/getting-started/installation] to detect tailwind classes inside the cva function.

I tried to translate their neovim instructions to work with the "patterns" feature in this library but it doesn't seem to work. Can you help me understand what I'm doing wrong?

  {
    'luckasRanarison/tailwind-tools.nvim',
    name = 'tailwind-tools',
    build = ':UpdateRemotePlugins',
    dependencies = {
      'nvim-treesitter/nvim-treesitter',
      'nvim-telescope/telescope.nvim', -- optional
      'neovim/nvim-lspconfig', -- optional
    },
    opts = {
      extensions = {
        patterns = {
          javascript = {
            { 'cva\\(([^)]*)\\)' },
            { 'cx\\(([^)]*)\\)' },
          },
          javascriptReact = {
            { 'cva\\(([^)]*)\\)' },
            { 'cx\\(([^)]*)\\)' },
          },
          typescript = {
            { 'cva\\(([^)]*)\\)' },
            { 'cx\\(([^)]*)\\)' },
          },
          typescriptreact = {
            { 'cva\\(([^)]*)\\)' },
            { 'cx\\(([^)]*)\\)' },
          },
        },
      },
    },
  },
luckasRanarison commented 1 month ago

Do you want to make the language server work for things inside the function .i.e get auto complete, diagnostics, etc or do you just want concealing?

If you want to make the language server work, you need to manually configure it by adding experimentalRegex in the server configuration. In the future this could be handled directly by the plugin without configuration #45 but that's the only way to extend the server for now.

If you want to get concealing, we can just extend the class queries.

Also, Lua pattern are similar to regex but they're not the same, you're using regex in your example.

NickyMeuleman commented 5 days ago

I had the same question. Tried the standard setup, and when that didn't work I started looking online.

My setup that does not work:

lspconfig["tailwindcss"].setup({
  capabilities = capabilities,
  settings = {
    tailwindCSS = {
      experimental = {
        classRegex = {
          -- https://cva.style/docs/getting-started/installation
          { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" },
        },
      },
    },
  },
})

The goal: having the lsp work in strings inside calls to cva() For example:

const thing = cva(
  [
    "my-4",
    "rounded-r",
    "border-l-2",
    "border-l-primary",
    "bg-primary",
    "bg-opacity-5",
    "p-4",
    "italic",
  ],
);

So the goal is: Calling the lsp popup for each class here shows me the real CSS that is applied, including for my extended colours (here: primary)

willdavidow commented 5 days ago

FWIW, this is what's in my tailwind lsp config and it works for cva:

lsp-settings/tailwindcss.lua

return {
  settings = {
    tailwindCSS = {
      lint = {
        cssConflict = "warning",
        invalidApply = "error",
        invalidConfigPath = "error",
        invalidScreen = "error",
        invalidTailwindDirective = "error",
        invalidVariant = "error",
        recommendedVariantOrder = "warning",
      },
      experimental = {
        classRegex = {
          "tw`([^`]*)",
          'tw="([^"]*)',
          'tw={"([^"}]*)',
          "tw\\.\\w+`([^`]*)",
          "tw\\(.*?\\)`([^`]*)",
          { "clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
          { "classnames\\(([^)]*)\\)", "'([^']*)'" },
          { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" },
          { "cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
        },
      },
    },
  },
}

tailwind-tools.lua

return {
  "luckasRanarison/tailwind-tools.nvim",
  enabled = true,
  build = ":UpdateRemotePlugins",
  event = "VeryLazy",
  dependencies = { "nvim-treesitter/nvim-treesitter" },
  opts = {}, -- your configuration
}
image
ajatkj commented 4 days ago

Hi @willdavidow For some reason, this is not working for me as well. Intellisense works inside the tsx className="..." property but not inside cva or clsx functions. I have copied your configuration from above.

What is the version of tailwindcss language server installed? Mine is 0.0.26 which seems to be the latest version.

image

My config-

lspconfig.lua

["tailwindcss"] = function()
  lspconfig["tailwindcss"].setup({
    capabilities = capabilities,
    settings = {
      tailwindCSS = {
        lint = {
          cssConflict = "warning",
          invalidApply = "error",
          invalidConfigPath = "error",
          invalidScreen = "error",
          invalidTailwindDirective = "error",
          invalidVariant = "error",
          recommendedVariantOrder = "warning",
        },
        experimental = {
          classRegex = {
            "tw`([^`]*)",
            'tw="([^"]*)',
            'tw={"([^"}]*)',
            "tw\\.\\w+`([^`]*)",
            "tw\\(.*?\\)`([^`]*)",
            { "clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
            { "classnames\\(([^)]*)\\)", "'([^']*)'" },
            { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" },
            { "cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
          },
        },
      },
    },
  })
end,

tailwind-tools.lua

return {
  "luckasRanarison/tailwind-tools.nvim",
  name = "tailwind-tools",
  build = ":UpdateRemotePlugins",
  dependencies = {
    "nvim-treesitter/nvim-treesitter",
    "neovim/nvim-lspconfig",
  },
  opts = {
    document_color = {
      enabled = true, -- can be toggled by commands
      kind = "background", -- "inline" | "foreground" | "background"
      inline_symbol = "󰝤 ", -- only used in inline mode
      debounce = 200, -- in milliseconds, only applied in insert mode
    },
    conceal = {
      enabled = false, -- can be toggled by commands
      min_length = 80, -- only conceal classes exceeding the provided length
      symbol = "󱏿", -- only a single character is allowed
      highlight = { -- extmark highlight options, see :h 'highlight'
        fg = "#38BDF8",
      },
    },
  },
}

I am not sure if there is anything else I am missing but haven't got it to work for a while now (which is frustrating!)

willdavidow commented 4 days ago

I'm on the same version of the tailwindcss LSP - it's almost like those settings aren't being applied for your setup. I'd maybe check your full settings and how/if the individual LSP's settings are being loaded.

This isn't my full lspconfig but I'm applying some specific settings for tailwind and telling it which server configs need to be loaded:

    -- setup lsp servers
    for _, server in pairs(servers) do
      local opts = {
        on_attach = on_attach,
        capabilities = common_capabilities(),
      }

      local require_ok, settings = pcall(require, "wd.plugins.lsp-settings." .. server)
      if require_ok then
        opts = vim.tbl_deep_extend("force", settings, opts)
      end

      if server == "tailwindcss" then
        opts.filetypes =
          { "html", "mdx", "javascript", "typescript", "javascriptreact", "typescriptreact", "vue", "svelte" }
      end

      if server == "graphql" then
        opts.filetypes =
          { "graphql", "gql", "javascript", "typescript", "javascriptreact", "typescriptreact", "vue", "svelte" }
      end

      if server == "lua_ls" then
        require("lazydev").setup {}
      end

      lspconfig[server].setup(opts)
    end
  end,
}
luckasRanarison commented 4 days ago

The plugin overrides LSP settings by default. You should configure the server this way:

return {
  "luckasRanarison/tailwind-tools.nvim",
  name = "tailwind-tools",
  opts = {
    server = {
      settings = {
        experimental = {
          classRegex = {
            "tw`([^`]*)",
            'tw="([^"]*)',
            'tw={"([^"}]*)',
            "tw\\.\\w+`([^`]*)",
            "tw\\(.*?\\)`([^`]*)",
            { "clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
            { "classnames\\(([^)]*)\\)", "'([^']*)'" },
            { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" },
            { "cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" },
          },
        },
      },
    },
  },
}
ajatkj commented 4 days ago

@luckasRanarison Thanks this works!