{ ... }:
{
  youthlic.plugins.mini-ai = {
    enable = true;
    luaConfig.pre =
      #lua
      ''
        do
          local ai = require("mini.ai")
          _M.__coding_plugin_mini_ai_opts = {
            n_lines = 500,
            custom_textobjects = {
              o = ai.gen_spec.treesitter({ -- code block
                a = { "@block.outer", "@conditional.outer", "@loop.outer" },
                i = { "@block.inner", "@conditional.inner", "@loop.inner" },
              }),
              f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }), -- function
              c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), -- class
              t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" }, -- tags
              d = { "%f[%d]%d+" }, -- digits
              e = { -- Word with case
                { "%u[%l%d]+%f[^%l%d]", "%f[%S][%l%d]+%f[^%l%d]", "%f[%P][%l%d]+%f[^%l%d]", "^[%l%d]+%f[^%l%d]" },
                "^().*()$",
              },
              g = function(ai_type)
                local start_line, end_line = 1, vim.fn.line("$")
                if ai_type == "i" then
                  local first_nonblank, last_nonblank = vim.fn.nextnonblank(start_line), vim.fn.prevnonblank(end_line)
                  if first_nonblank == 0 or last_nonblank == 0 then
                    return { from = { line = start_line, col = 1 } }
                  end
                  start_line, end_line = first_nonblank, last_nonblank
                end

                local to_col = math.max(vim.fn.getline(end_line):len(), 1)
                return {
                  from = {
                    line = start_line,
                    col = 1,
                  },
                  to = {
                    line = end_line,
                    col = to_col,
                  },
                }
              end, -- buffer
              u = ai.gen_spec.function_call(), -- u for "Usage"
              U = ai.gen_spec.function_call({ name_pattern = "[%w_]" }), -- without dot in function name
            },
          }
        end
      '';
    settings = {
      __raw =
        #lua
        "_M.__coding_plugin_mini_ai_opts";
    };
    luaConfig.post =
      #lua
      ''
        _M.on_load("which-key", function()
          local opts = _M.__coding_plugin_mini_ai_opts
          local objects = {
            { " ", desc = "whitespace" },
            { '"', desc = '" string' },
            { "'", desc = "' string" },
            { "(", desc = "() block" },
            { ")", desc = "() block with ws" },
            { "<", desc = "<> block" },
            { ">", desc = "<> block with ws" },
            { "?", desc = "user prompt" },
            { "U", desc = "use/call without dot" },
            { "[", desc = "[] block" },
            { "]", desc = "[] block with ws" },
            { "_", desc = "underscore" },
            { "`", desc = "` string" },
            { "a", desc = "argument" },
            { "b", desc = ")]} block" },
            { "c", desc = "class" },
            { "d", desc = "digit(s)" },
            { "e", desc = "CamelCase / snake_case" },
            { "f", desc = "function" },
            { "g", desc = "entire file" },
            { "i", desc = "indent" },
            { "o", desc = "block, conditional, loop" },
            { "q", desc = "quote `\"'" },
            { "t", desc = "tag" },
            { "u", desc = "use/call" },
            { "{", desc = "{} block" },
            { "}", desc = "{} with ws" },
          }

          ---@type wk.Spec[]
          local ret = { mode = { "o", "x" } }
          ---@type table<string, string>
          local mappings = vim.tbl_extend("force", {}, {
            around = "a",
            inside = "i",
            around_next = "an",
            inside_next = "in",
            around_last = "al",
            inside_last = "il",
          }, opts.mappings or {})
          mappings.goto_left = nil
          mappings.goto_right = nil

          for name, prefix in pairs(mappings) do
            name = name:gsub("^around_", ""):gsub("^inside_", "")
            ret[#ret + 1] = { prefix, group = name }
            for _, obj in ipairs(objects) do
              local desc = obj.desc
              if prefix:sub(1, 1) == "i" then
                desc = desc:gsub(" with ws", "")
              end
              ret[#ret + 1] = { prefix .. obj[1], desc = obj.desc }
            end
          end
          require("which-key").add(ret, { notify = false })
        end)
      '';
  };
}
