local O=(require("\099\104\097\105\046\111\112\116\105\111\110\115")).makeopt return{options={float_border=O({"\115\105\110\103\108\101","\098\111\114\100\101\114 \102\111\114 \102\108\111\097\116\105\110\103 \119\105\110\100\111\119\115",function(O)return vim.tbl_contains({"\115\105\110\103\108\101","\100\111\117\098\108\101";"\114\111\117\110\100\101\100";"\115\111\108\105\100"},O)end})},setup=function(O)vim.opt.encoding="\117\116\102-\056"vim.opt.title=true vim.opt.titlestring="\037\123\101\120\112\097\110\100\040\"\037\058\112\058~\058\046\"\041\125 \194\183 \110\118\105\109"vim.opt.errorbells=false vim.opt.mouse="\110\118"vim.opt.keywordprg="\058\118\101\114\116\105\099\097\108 \098\111\116\114\105\103\104\116 \104\101\108\112"vim.opt.termguicolors=true vim.opt.number=true vim.opt.relativenumber=false vim.opt.numberwidth=3 vim.o.scrolloff=5 vim.o.sidescrolloff=15 vim.o.pumheight=15 vim.opt.wildoptions={"\102\117\122\122\121";"\112\117\109","\116\097\103\102\105\108\101"}vim.opt.wildmode="\108\111\110\103\101\115\116\058\102\117\108\108\044\102\117\108\108"vim.opt.completeopt={"\102\117\122\122\121";"\109\101\110\117","\109\101\110\117\111\110\101","\110\111\105\110\115\101\114\116";"\112\114\101\118\105\101\119"}vim.o.splitbelow=true vim.o.splitright=true vim.opt.incsearch=true vim.opt.hlsearch=true vim.o.ignorecase=true vim.o.smartcase=true vim.opt.inccommand="\115\112\108\105\116"vim.opt.foldenable=false vim.opt.foldlevelstart=0 vim.opt.foldnestmax=4 vim.opt.foldmethod="\101\120\112\114"vim.opt.foldexpr="\110\118\105\109\095\116\114\101\101\115\105\116\116\101\114\035\102\111\108\100\101\120\112\114\040\041"vim.opt.iskeyword:remove("\095")vim.opt.virtualedit="\098\108\111\099\107"vim.o.shiftwidth=2 vim.o.tabstop=2 vim.o.softtabstop=0 vim.o.expandtab=true vim.o.smartindent=true vim.o.smarttab=true vim.opt.breakindent=true vim.o.wrap=false vim.o.signcolumn="\121\101\115\058\049"vim.opt.shortmess:append("\115\073")vim.opt.formatoptions="\116\099\114\113\106"vim.opt.conceallevel=2 vim.opt.concealcursor="\099"vim.g.have_nerd_font=true vim.opt.updatetime=250 vim.opt.timeout=false vim.opt.timeoutlen=0 vim.opt.showmode=false vim.opt.showcmd=false vim.o.showtabline=2 vim.o.cmdheight=0 vim.o.laststatus=3 vim.opt.grepprg=vim.fn.executable("\114\103")==1 and"\114\103 --\118\105\109\103\114\101\112"or"\103\114\101\112 -\110 \036\042 \047\100\101\118\047\110\117\108\108"vim.opt.grepformat="\037\102\058\037\108\058\037\099\058\037\109"vim.opt.spelllang={"\101\110"}vim.opt.spelloptions:append("\110\111\112\108\097\105\110\098\117\102\102\101\114")vim.opt.list=true vim.opt.shell=os.getenv("\083\072\069\076\076")or"\047\098\105\110\047\115\104"vim.opt.swapfile=false vim.opt.backup=false vim.opt.undodir=vim.fn.stdpath("\115\116\097\116\101").."\047\117\110\100\111\100\105\114"vim.opt.undofile=true vim.opt.hidden=true local V={solid={style="\115\111\108\105\100";vert="\226\150\136";vertleft="\226\150\136",vertright="\226\150\136",horiz="\226\150\132";horizup="\226\150\128",horizdown="\226\150\132";verthoriz="\226\150\136";topleft="\226\150\132",topright="\226\150\132",botleft="\226\150\128",botright="\226\150\128";bottom="\226\150\128"};single={style="\115\105\110\103\108\101",vert="\226\148\130",vertleft="\226\148\164";vertright="\226\148\156";horiz="\226\148\128";horizup="\226\148\180",horizdown="\226\148\172",verthoriz="\226\148\188",topleft="\226\148\140";topright="\226\148\144";botleft="\226\148\148";botright="\226\148\152"};double={style="\100\111\117\098\108\101";vert="\226\149\145",vertleft="\226\149\163",vertright="\226\149\160";horiz="\226\149\144";horizup="\226\149\169";horizdown="\226\149\166";verthoriz="\226\149\172";topleft="\226\149\148",topright="\226\149\151";botleft="\226\149\154";botright="\226\149\157"},rounded={style="\114\111\117\110\100\101\100",vert="\226\148\130";vertleft="\226\148\164",vertright="\226\148\156";horiz="\226\148\128",horizup="\226\148\180",horizdown="\226\148\172";verthoriz="\226\148\188";topleft="\226\149\173",topright="\226\149\174",botleft="\226\149\176",botright="\226\149\175"}}vim.g.bc=V[O.float_border]or V.single vim.g.bc_all={vim.g.bc.topleft;vim.g.bc.top or vim.g.bc.horiz;vim.g.bc.topright,vim.g.bc.vert;vim.g.bc.botright;vim.g.bc.bottom or vim.g.bc.horiz,vim.g.bc.botleft,vim.g.bc.vert}vim.opt.fillchars:append({horiz=vim.g.bc.horiz;horizup=vim.g.bc.horizup;horizdown=vim.g.bc.horizdown,vert=vim.g.bc.vert,vertright=vim.g.bc.vertright,vertleft=vim.g.bc.vertleft,verthoriz=vim.g.bc.verthoriz})vim.g.rustfmt_autosave=1 vim.g.loaded_node_provider=0 vim.g.loaded_perl_provider=0 vim.g.loaded_python_provider=0 vim.g.loaded_python3_provider=0 vim.g.loaded_ruby_provider=0 vim.g.markdown_recommended_style=0 local G={normal={type="\098\108\111\099\107"},insert={type="\118\101\114\116\105\099\097\108";size=200,animate={wait=50;on=150,off=150}};replace={type="\104\111\114\105\122\111\110\116\097\108";size=20};operator={type="\104\111\114\105\122\111\110\116\097\108",size=50},showmatch={type="\098\108\111\099\107"}}local L={normal="\110-\118-\099",insert="\105-\099\105-\118\101",replace="\114-\099\114",operator="\111";showmatch="\115\109"}local U={block="\098\108\111\099\107";vertical="\118\101\114";horizontal="\104\111\114"}local o=(vim.iter(pairs(G))):fold("",function(O,V,G)vim.validate("\109\111\100\101",V,function(O)return vim.tbl_contains({"\110\111\114\109\097\108","\105\110\115\101\114\116","\114\101\112\108\097\099\101","\111\112\101\114\097\116\111\114";"\115\104\111\119\109\097\116\099\104"},O)end,"\118\097\108\105\100 \109\111\100\101")vim.validate("\111\112\116\115",G,function(O)vim.validate("\116\121\112\101",O.type,function(O)return vim.tbl_contains({"\098\108\111\099\107","\118\101\114\116\105\099\097\108","\104\111\114\105\122\111\110\116\097\108"},O)end,"\118\097\108\105\100 \116\121\112\101")if O.type~="\098\108\111\099\107"then vim.validate("\115\105\122\101",O.size,function(O)return type(O)=="\110\117\109\098\101\114"end,"\118\097\108\105\100 \115\105\122\101 \119\105\116\104 \116\121\112\101 ~\061 \098\108\111\099\107")end if O.animate then vim.validate("\097\110\105\109\097\116\101",O.animate,function(O)vim.validate("\119\097\105\116",O.wait,"\110\117\109\098\101\114")vim.validate("\111\110",O.on,"\110\117\109\098\101\114")vim.validate("\111\102\102",O.off,"\110\117\109\098\101\114")return true end,"\118\097\108\105\100 \097\110\105\109\097\116\105\111\110")end return true end,"\118\097\108\105\100 \111\112\116\115")if#O>0 then O=O.."\044"end local o=string.format("\037\115\058\037\115",L[V],G.type~="\098\108\111\099\107"and string.format("\037\115\037\100",U[G.type],G.size)or U[G.type])if G.animate then local O=G.animate local V=string.format("\098\108\105\110\107\119\097\105\116\037\100-\098\108\105\110\107\111\110\037\100-\098\108\105\110\107\111\102\102\037\100",O.wait,O.on,O.off)o=o..("-"..V)end return O..o end)vim.opt.guicursor=o vim.diagnostic.config({virtual_text={hl_mode="\099\111\109\098\105\110\101"};signs=true;float={border=vim.g.bc_all;header="";prefix=function(O,V)return string.format("\037\100\046 ",V),"\076\105\110\101\078\114"end}})end}
local makeopt = require("chai.options").makeopt

return {
  options = {
    float_border = makeopt({
      "single",
      "border for floating windows",
      function(v)
        return vim.tbl_contains({ "single", "double", "rounded", "solid" }, v)
      end,
    }),
  },
  setup = function(props)
    vim.opt.encoding = "utf-8"

    vim.opt.title = true
    vim.opt.titlestring = '%{expand("%:p:~:.")} · nvim'
    vim.opt.errorbells = false
    vim.opt.mouse = "nv"

    vim.opt.keywordprg = ":vertical botright help"

    -- true colors
    vim.opt.termguicolors = true

    -- line numbers
    vim.opt.number = true
    vim.opt.relativenumber = false
    vim.opt.numberwidth = 3

    -- scroll offsets
    vim.o.scrolloff = 5
    vim.o.sidescrolloff = 15

    -- completion height
    vim.o.pumheight = 15
    vim.opt.wildoptions = { "fuzzy", "pum", "tagfile" }
    vim.opt.wildmode = "longest:full,full"
    vim.opt.completeopt = { "fuzzy", "menu", "menuone", "noinsert", "preview" }

    -- split directions
    vim.o.splitbelow = true
    vim.o.splitright = true

    -- search settings
    vim.opt.incsearch = true
    vim.opt.hlsearch = true
    vim.o.ignorecase = true
    vim.o.smartcase = true
    -- substitution with preview window
    vim.opt.inccommand = "split"

    -- folding
    vim.opt.foldenable = false
    vim.opt.foldlevelstart = 0
    vim.opt.foldnestmax = 4
    -- vim.opt.foldmethod = 'marker'

    -- enable treesitter folds
    vim.opt.foldmethod = "expr"
    vim.opt.foldexpr = "nvim_treesitter#foldexpr()"

    -- redefine word boundaries - '_' is a word separator, this helps with snake_case
    vim.opt.iskeyword:remove("_")

    -- allow cursor to move paste the end of the line in visual block mode
    vim.opt.virtualedit = "block"

    -- indentations settings
    vim.o.shiftwidth = 2
    vim.o.tabstop = 2
    vim.o.softtabstop = 0 -- dont insert spaces on <tab>
    vim.o.expandtab = true
    vim.o.smartindent = true
    vim.o.smarttab = true
    -- Enable break indent
    vim.opt.breakindent = true
    vim.o.wrap = false

    -- always show 1 column of sign column (gitsigns, etc.)
    vim.o.signcolumn = "yes:1"

    -- hide search notices, intro
    vim.opt.shortmess:append("sI")

    vim.opt.formatoptions = "tcrqj"

    -- hide extra text
    vim.opt.conceallevel = 2
    vim.opt.concealcursor = "c"

    -- nice font icons or something
    vim.g.have_nerd_font = true

    -- Decrease update time
    vim.opt.updatetime = 250
    -- Decrease mapped sequence wait time
    -- Displays which-key popup sooner
    vim.opt.timeout = false
    vim.opt.timeoutlen = 0

    -- Don't show the mode, since it's already in the status line
    vim.opt.showmode = false
    vim.opt.showcmd = false
    vim.o.showtabline = 2
    vim.o.cmdheight = 0
    -- global statusline
    vim.o.laststatus = 3

    -- use rg for grepping
    vim.opt.grepprg = vim.fn.executable("rg") == 1 and "rg --vimgrep" or "grep -n $* /dev/null"
    vim.opt.grepformat = "%f:%l:%c:%m"

    -- let me have spelling checking for english
    vim.opt.spelllang = { "en" }
    vim.opt.spelloptions:append("noplainbuffer")

    -- indent blank line imporvments
    vim.opt.list = true

    vim.opt.shell = os.getenv("SHELL") or "/bin/sh"

    -- disable swap & backup, and configure undo files
    vim.opt.swapfile = false
    vim.opt.backup = false
    vim.opt.undodir = vim.fn.stdpath("state") .. "/undodir"
    vim.opt.undofile = true
    -- dont unload abandoned buffers
    vim.opt.hidden = true

    ---@type { [string]: { style: string, ['vert'|'vertleft'|'vertright'|'horiz'|'horizup'|'horizdown'|'verthoriz'|'topleft'|'topright'|'botleft'|'botright']: string, bottom?: string } }
    local borderchars = {
      solid = {
        style = "solid",
        vert = "█",
        vertleft = "█",
        vertright = "█",
        horiz = "▄",
        horizup = "▀",
        horizdown = "▄",
        verthoriz = "█",
        topleft = "▄",
        topright = "▄",
        botleft = "▀",
        botright = "▀",
        bottom = "▀",
      },
      single = {
        style = "single",
        vert = "│",
        vertleft = "┤",
        vertright = "├",
        horiz = "─",
        horizup = "┴",
        horizdown = "┬",
        verthoriz = "┼",
        topleft = "┌",
        topright = "┐",
        botleft = "└",
        botright = "┘",
      },
      double = {
        style = "double",
        vert = "║",
        vertleft = "╣",
        vertright = "╠",
        horiz = "═",
        horizup = "╩",
        horizdown = "╦",
        verthoriz = "╬",
        topleft = "╔",
        topright = "╗",
        botleft = "╚",
        botright = "╝",
      },
      rounded = {
        style = "rounded",
        vert = "│",
        vertleft = "┤",
        vertright = "├",
        horiz = "─",
        horizup = "┴",
        horizdown = "┬",
        verthoriz = "┼",
        topleft = "╭",
        topright = "╮",
        botleft = "╰",
        botright = "╯",
      },
    }

    -- my custom borderchars
    vim.g.bc = borderchars[props.float_border] or borderchars.single
    vim.g.bc_all = {
      vim.g.bc.topleft,
      vim.g.bc.top or vim.g.bc.horiz,
      vim.g.bc.topright,
      vim.g.bc.vert,
      vim.g.bc.botright,
      vim.g.bc.bottom or vim.g.bc.horiz,
      vim.g.bc.botleft,
      vim.g.bc.vert,
    }
    vim.opt.fillchars:append({
      horiz = vim.g.bc.horiz,
      horizup = vim.g.bc.horizup,
      horizdown = vim.g.bc.horizdown,
      vert = vim.g.bc.vert,
      vertright = vim.g.bc.vertright,
      vertleft = vim.g.bc.vertleft,
      verthoriz = vim.g.bc.verthoriz,
    })

    -- rust save
    vim.g.rustfmt_autosave = 1

    -- disable remote plugin providers
    vim.g.loaded_node_provider = 0
    vim.g.loaded_perl_provider = 0
    vim.g.loaded_python_provider = 0
    vim.g.loaded_python3_provider = 0
    vim.g.loaded_ruby_provider = 0

    -- fix markfown stuff
    vim.g.markdown_recommended_style = 0

    -- cursor
    local guicursor_opts = {
      normal = {
        type = "block",
      },
      insert = {
        type = "vertical",
        size = 200,
        animate = {
          wait = 50,
          on = 150,
          off = 150,
        },
      },
      replace = {
        type = "horizontal",
        size = 20,
      },
      operator = {
        type = "horizontal",
        size = 50,
      },
      showmatch = {
        type = "block",
      },
    }

    local mode_lookup = {
      normal = "n-v-c",
      insert = "i-ci-ve",
      replace = "r-cr",
      operator = "o",
      showmatch = "sm",
    }
    local type_lookup = {
      block = "block",
      vertical = "ver",
      horizontal = "hor",
    }
    local guicusor = vim.iter(pairs(guicursor_opts)):fold("", function(str, mode, opts)
      vim.validate("mode", mode, function(v)
        return vim.tbl_contains({ "normal", "insert", "replace", "operator", "showmatch" }, v)
      end, "valid mode")
      vim.validate("opts", opts, function(v)
        vim.validate("type", v.type, function(t)
          return vim.tbl_contains({ "block", "vertical", "horizontal" }, t)
        end, "valid type")
        if v.type ~= "block" then
          vim.validate("size", v.size, function(s)
            return type(s) == "number"
          end, "valid size with type ~= block")
        end

        if v.animate then
          vim.validate("animate", v.animate, function(anim)
            vim.validate("wait", anim.wait, "number")
            vim.validate("on", anim.on, "number")
            vim.validate("off", anim.off, "number")
            return true
          end, "valid animation")
        end

        return true
      end, "valid opts")
      if #str > 0 then
        str = str .. ","
      end
      local s = string.format(
        "%s:%s",
        mode_lookup[mode],
        opts.type ~= "block" and string.format("%s%d", type_lookup[opts.type], opts.size) or type_lookup[opts.type]
      )

      if opts.animate then
        local anim = opts.animate
        local anim_str = string.format("blinkwait%d-blinkon%d-blinkoff%d", anim.wait, anim.on, anim.off)
        s = s .. "-" .. anim_str
      end

      return str .. s
    end)

    vim.opt.guicursor = guicusor

    -- lsp
    vim.diagnostic.config({
      virtual_text = {
        hl_mode = "combine",
      },
      -- virtual_lines = {
      --   current_line = true,
      -- },
      signs = true,
      float = {
        border = vim.g.bc_all,
        header = "",
        prefix = function(_, i)
          return string.format("%d. ", i), "LineNr"
        end,
      },
    })
  end,
}
