vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1

-- Set highlight on search
vim.o.hlsearch = false

-- Make line numbers default
vim.wo.number = true

-- Enable mouse mode
vim.o.mouse = 'a'

-- Enable break indent
vim.o.breakindent = true

-- Save undo history
vim.o.undofile = true

-- Case insensitive searching UNLESS /C or capital in search
vim.o.ignorecase = true
vim.o.smartcase = true

-- Keep signcolumn on by default
vim.wo.signcolumn = 'yes'

-- Set completeopt to have a better completion experience
vim.o.completeopt = 'menuone,noselect,noinsert'

-- Use terminal colors
vim.o.termguicolors = true

-- Tabs
vim.o.shiftwidth = 4
vim.o.smarttab = true
vim.o.tabstop = 4
vim.o.expandtab = true
vim.o.softtabstop = 4

-- Show cursor line
vim.o.cursorline = true

vim.o.pumheight = 10

vim.o.relativenumber = true
vim.o.scrolloff = 8

vim.o.showmode = false

vim.o.showtabline = 0

vim.o.wrap = true

vim.o.foldmethod = "expr"
vim.o.foldexpr = "nvim_treesitter#foldexpr()"
vim.o.foldlevelstart = 99

-- show cursor line only in active window
local cursorLineGrp = vim.api.nvim_create_augroup("CursorLine", { clear = true })
vim.api.nvim_create_autocmd(
    { "InsertLeave", "WinEnter" },
    { pattern = "*", command = "set cursorline", group = cursorLineGrp }
)
vim.api.nvim_create_autocmd(
    { "InsertEnter", "WinLeave" },
    { pattern = "*", command = "set nocursorline", group = cursorLineGrp }
)

-- Auto format on save
vim.cmd [[autocmd BufWritePre * lua vim.lsp.buf.format()]]

-- Auto update on file changes
vim.o.autoread = true
vim.api.nvim_create_autocmd({ "BufEnter", "CursorHold", "CursorHoldI", "FocusGained" }, {
    command = "if mode() != 'c' | checktime | endif",
    pattern = { "*" },
})
vim.api.nvim_create_autocmd({ "FileChangedShellPost" },
    { command = 'echohl WarningMsg | echo "File changed on disk. Buffer reloaded." | echohl None', pattern = { "*" }, })
-------------------------------------------------------------------
-- Plugin management
-------------------------------------------------------------------
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'

if not vim.loop.fs_stat(lazypath) then
    vim.fn.system {
        'git',
        'clone',
        '--filter=blob:none',
        'https://github.com/folke/lazy.nvim.git',
        '--branch=stable', -- latest stable release
        lazypath,
    }
end

vim.opt.rtp:prepend(lazypath)

-------------------------------------------------------------------
-- Plugin installation
-------------------------------------------------------------------
require('lazy').setup({

    -- Color scheme ------------------------------------------
    {
        dir = "~/linuxbox/nightly_cm.nvim",
        lazy = false,
        priority = 1000,
        config = function()
            vim.cmd.colorscheme 'nightly_cm'
        end,
    },

    -- LSP ----------------------------------------------------
    {
        'neovim/nvim-lspconfig',
        event = { "BufReadPre", "BufNewFile" },
        dependencies = {
            { 'williamboman/mason.nvim', config = true },
            'williamboman/mason-lspconfig.nvim',
        },
    },

    {
        "L3MON4D3/LuaSnip",
        -- follow latest release.
        version = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release)
        -- install jsregexp (optional!).
        build = "make install_jsregexp"
    },

    {
        'hrsh7th/nvim-cmp',
        dependencies = {
            'onsails/lspkind.nvim',
            'saadparwaiz1/cmp_luasnip',
            'hrsh7th/cmp-nvim-lsp',
            'rafamadriz/friendly-snippets',
            'hrsh7th/cmp-buffer',
            'hrsh7th/cmp-path',
            'hrsh7th/cmp-cmdline',
        },
    },

    -- {
    --     'zbirenbaum/copilot.lua',
    --     config = function()
    --         require('copilot').setup {
    --             suggestion = { enabled = false },
    --             panel = { enabled = false },
    --             filetypes = { markdown = true },
    --         }
    --     end,
    -- },

    -- {
    --     'zbirenbaum/copilot-cmp',
    --     config = function() require('copilot_cmp').setup() end,
    -- },
    {
        "ahmedkhalf/project.nvim",
        config = function()
            require("project_nvim").setup {
                sync_root_with_cwd = true,
                respect_buf_cwd = true,
                update_focused_file = {
                    enable = true,
                    update_root = true
                },
            }
        end
    },

    {
        -- Highlight, edit, and navigate code
        'nvim-treesitter/nvim-treesitter',
        dependencies = {
            'nvim-treesitter/nvim-treesitter-textobjects',
        },
        build = ':TSUpdate',
    },

    {
        "simrat39/rust-tools.nvim",
    },

    {
        "ray-x/lsp_signature.nvim",
        config = function()
            require "lsp_signature".setup {
                bind = true, -- This is mandatory, otherwise border config won't get registered.
                handler_opts = {
                    border = "solid"
                }
            }
        end
    },

    -- {
    --     "jay-babu/mason-null-ls.nvim",
    --     event = { "BufReadPre", "BufNewFile" },
    --     dependencies = {
    --         "williamboman/mason.nvim",
    --         "jose-elias-alvarez/null-ls.nvim",
    --     },
    --     config = function()
    --         require("mason").setup()
    --         require("mason-null-ls").setup({
    --             ensure_installed = {
    --                 -- Opt to list sources here, when available in mason.
    --             },
    --             automatic_installation = false,
    --             handlers = {},
    --         })
    --         require("null-ls").setup({
    --             sources = {
    --                 -- Anything not supported by mason.
    --             }
    --         })
    --     end,
    -- },

    -- File explorer -------------------------------------------
    -- {
    --     's1n7ax/nvim-window-picker',
    --     version = '2.*',
    --     config = function()
    --         require 'window-picker'.setup({
    --             filter_rules = {
    --                 include_current_win = false,
    --                 autoselect_one = true,
    --                 -- filter using buffer options
    --                 bo = {
    --                     -- if the file type is one of following, the window will be ignored
    --                     filetype = { 'neo-tree', "neo-tree-popup", "notify" },
    --                     -- if the buffer type is one of following, the window will be ignored
    --                     buftype = { 'terminal', "quickfix" },
    --                 },
    --             },
    --             highlights = {
    --                 statusline = {
    --                     unfocused = {
    --                         fg = '#d7af5f',
    --                         bg = '#262626',
    --                         bold = true,
    --                     },
    --                     focused = {
    --                         fg = '#d7af5f',
    --                         bg = '#262626',
    --                         bold = true,
    --                     },
    --                 },
    --             },
    --         })
    --     end,
    -- },
    {
        "ibhagwan/fzf-lua",
        -- optional for icon support
        dependencies = { "nvim-tree/nvim-web-devicons" },
        config = function()
            -- calling `setup` is optional for customization
            require("fzf-lua").setup({})
        end
    },

    {
        "nvim-neo-tree/neo-tree.nvim",
        branch = "v3.x",
        dependencies = {
            "nvim-lua/plenary.nvim",
            "nvim-tree/nvim-web-devicons",
            "MunifTanjim/nui.nvim",
        },
        config = function()
            require("neo-tree").setup {
                close_if_last_window = true,
                popup_border_style = "rounded",
                enable_git_status = true,
                enable_diagnostics = true,
                open_files_do_not_replace_types = { "terminal", "trouble", "qf" }, -- when opening files, do not use windows containing these filetypes or buftypes
                sort_case_insensitive = false,                                     -- used when sorting files and directories in the tree
                sort_function = nil,                                               -- use a custom function for sorting files and directories in the tree
                default_component_configs = {
                    container = {
                        enable_character_fade = true
                    },
                    indent = {
                        indent_size = 2,
                        padding = 1, -- extra padding on left hand side
                        -- indent guides
                        with_markers = true,
                        indent_marker = "│",
                        last_indent_marker = "└",
                        highlight = "NeoTreeIndentMarker",
                        -- expander config, needed for nesting files
                        with_expanders = nil, -- if nil and file nesting is enabled, will enable expanders
                        expander_collapsed = "",
                        expander_expanded = "",
                        expander_highlight = "NeoTreeExpander",
                    },
                    icon = {
                        folder_closed = "",
                        folder_open = "",
                        folder_empty = "󰜌",
                        provider = function(icon, node, state) -- default icon provider utilizes nvim-web-devicons if available
                            if node.type == "file" or node.type == "terminal" then
                                local success, web_devicons = pcall(require, "nvim-web-devicons")
                                local name = node.type == "terminal" and "terminal" or node.name
                                if success then
                                    local devicon, hl = web_devicons.get_icon(name)
                                    icon.text = devicon or icon.text
                                    icon.highlight = hl or icon.highlight
                                end
                            end
                        end,
                        -- The next two settings are only a fallback, if you use nvim-web-devicons and configure default icons there
                        -- then these will never be used.
                        default = "*",
                        highlight = "NeoTreeFileIcon"
                    },
                    modified = {
                        symbol = "[+]",
                        highlight = "NeoTreeModified",
                    },
                    name = {
                        trailing_slash = false,
                        use_git_status_colors = true,
                        highlight = "NeoTreeFileName",
                    },
                    git_status = {
                        symbols = {
                            -- Change type
                            added     = "", -- or "✚", but this is redundant info if you use git_status_colors on the name
                            modified  = "", -- or "", but this is redundant info if you use git_status_colors on the name
                            deleted   = "✖", -- this can only be used in the git_status source
                            renamed   = "󰁕", -- this can only be used in the git_status source
                            -- Status type
                            untracked = "",
                            ignored   = "",
                            unstaged  = "󰄱",
                            staged    = "",
                            conflict  = "",
                        }
                    },
                    -- If you don't want to use these columns, you can set `enabled = false` for each of them individually
                    file_size = {
                        enabled = true,
                        required_width = 64, -- min width of window required to show this column
                    },
                    type = {
                        enabled = true,
                        required_width = 122, -- min width of window required to show this column
                    },
                    last_modified = {
                        enabled = true,
                        required_width = 88, -- min width of window required to show this column
                    },
                    created = {
                        enabled = true,
                        required_width = 110, -- min width of window required to show this column
                    },
                    symlink_target = {
                        enabled = false,
                    },
                },
                commands = {
                    parent_or_close = function(state)
                        local node = state.tree:get_node()
                        if (node.type == "directory" or node:has_children()) and node:is_expanded() then
                            state.commands.toggle_node(state)
                        else
                            require("neo-tree.ui.renderer").focus_node(state, node:get_parent_id())
                        end
                    end,
                    child_or_open = function(state)
                        local node = state.tree:get_node()
                        if node.type == "directory" or node:has_children() then
                            if not node:is_expanded() then -- if unexpanded, expand
                                state.commands.toggle_node(state)
                            else                           -- if expanded and has children, seleect the next child
                                require("neo-tree.ui.renderer").focus_node(state, node:get_child_ids()[1])
                            end
                        else -- if not a directory just open it
                            state.commands.open(state)
                        end
                    end,
                    copy_selector = function(state)
                        local node = state.tree:get_node()
                        local filepath = node:get_id()
                        local filename = node.name
                        local modify = vim.fn.fnamemodify

                        local results = {
                            e = { val = modify(filename, ":e"), msg = "Extension only" },
                            f = { val = filename, msg = "Filename" },
                            F = { val = modify(filename, ":r"), msg = "Filename w/o extension" },
                            h = { val = modify(filepath, ":~"), msg = "Path relative to Home" },
                            p = { val = modify(filepath, ":."), msg = "Path relative to CWD" },
                            P = { val = filepath, msg = "Absolute path" },
                        }

                        local messages = {
                            { "\nChoose to copy to clipboard:\n", "Normal" },
                        }
                        for i, result in pairs(results) do
                            if result.val and result.val ~= "" then
                                vim.list_extend(messages, {
                                    { ("%s."):format(i),           "Identifier" },
                                    { (" %s: "):format(result.msg) },
                                    { result.val,                  "String" },
                                    { "\n" },
                                })
                            end
                        end
                        vim.api.nvim_echo(messages, false, {})
                        local result = results[vim.fn.getcharstr()]
                        if result and result.val and result.val ~= "" then
                            vim.notify("Copied: " .. result.val)
                            vim.fn.setreg("+", result.val)
                        end
                    end,
                },
                window = {
                    position = "float",
                    width = 40,
                    mappings = {
                        ["<space>"] = false, -- disable space until we figure out which-key disabling
                        h = "parent_or_close",
                        l = "child_or_open",
                        Y = "copy_selector",
                    },
                },
            }
        end,
    },


    -- GUI ------------------------------------------------------

    {
        'mrjones2014/smart-splits.nvim',
        opts = {
            at_edge = 'stop',
        }
    },

    {
        -- Set lualine as statusline
        'nvim-lualine/lualine.nvim',
        opts = {
            options = {
                icons_enabled = true,
                theme = 'nightly_cm',
                component_separators = '',
                section_separators = '',
                globalstatus = true,
            },
            sections = {
                lualine_a = { 'mode' },
                lualine_b = { 'branch', 'diff' },
                lualine_c = { 'diagnostics', 'filename' },
                lualine_x = {
                    {
                        -- Lsp server name .
                        function()
                            local msg = ''
                            local clients = vim.lsp.get_clients({ bufnr = 0 })
                            if next(clients) == nil then
                                return msg
                            end
                            for _, client in ipairs(clients) do
                                msg = msg .. client.name .. ", "
                            end
                            if msg == '' then
                                return msg
                            end
                            return msg:sub(1, -3)
                        end,
                        color = { fg = '#c6c6c6' },
                    },
                },
                lualine_y = { 'filetype' },
                lualine_z = { 'progress' }
            },
        },
    },

    {
        -- Adds git releated signs to the gutter, as well as utilities for managing changes
        'lewis6991/gitsigns.nvim',
        opts = {
            signs = {
                add = { text = "▎" },
                change = { text = "▎" },
                delete = { text = "▎" },
                topdelete = { text = "▎" },
                changedelete = { text = "▎" },
                untracked = { text = "▎" },
            },
            preview_config = {
                -- Options passed to nvim_open_win
                border = 'solid',
                style = 'minimal',
                relative = 'cursor',
                row = 0,
                col = 1
            },
            on_attach = function(bufnr)
                vim.keymap.set('n', '<leader>gp', require('gitsigns').prev_hunk,
                    { buffer = bufnr, desc = '[G]o to [P]revious Hunk' })
                vim.keymap.set('n', '<leader>gn', require('gitsigns').next_hunk,
                    { buffer = bufnr, desc = '[G]o to [N]ext Hunk' })
                vim.keymap.set('n', '<leader>ph', require('gitsigns').preview_hunk,
                    { buffer = bufnr, desc = '[P]review [H]unk' })
            end,
        },
    },

    {
        -- Add indentation guides even on blank lines
        'lukas-reineke/indent-blankline.nvim',
        main = "ibl",
        opts = {
            scope = {
                show_end = false,
            }
        }
    },

    {
        "norcalli/nvim-colorizer.lua",
        config = function()
            require("colorizer").setup()
        end,
    },

    {
        "folke/neodev.nvim",
        opts = {}
    },

    {
        "folke/which-key.nvim",
        event = "VeryLazy",
        init = function()
            vim.o.timeout = true
            vim.o.timeoutlen = 300
        end,
        opts = {
            -- your configuration comes here
            -- or leave it empty to use the default settings
            -- refer to the configuration section below
        }
    },

    {
        'MeanderingProgrammer/render-markdown.nvim',
        dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' }, -- if you use the mini.nvim suite
        -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.icons' }, -- if you use standalone mini plugins
        -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons
        ---@module 'render-markdown'
        ---@type render.md.UserConfig
        opts = {
            code = {
                enabled = true,
                sign = true,
                style = 'full',
                position = 'left',
                language_pad = 0,
                language_name = true,
                disable_background = { 'diff' },
                width = 'full',
                left_margin = 0,
                left_pad = 0,
                right_pad = 0,
                min_width = 0,
                border = 'thick',
                above = '▄',
                below = '▀',
                highlight = 'RenderMarkdownCode',
                highlight_inline = 'RenderMarkdownCodeInline',
                highlight_language = nil,
            },
        },
    },

    -- Utils ---------------------------------------------------
    {
        "max397574/better-escape.nvim",
        opts = { timeout = 300 }
    },

    { 'numToStr/Comment.nvim', opts = {} },

    -- {
    --     "kdheepak/lazygit.nvim",
    --     dependencies = {
    --         "nvim-lua/plenary.nvim",
    --     },
    -- },

    -- {
    --     'akinsho/toggleterm.nvim',
    --     version = "*",
    --     config = function()
    --         require("toggleterm").setup {
    --             open_mapping = [[<c-t>]],
    --             shade_terminals = false,
    --             highlights = {
    --                 Normal = {
    --                     guibg = "#262626",
    --                 },
    --                 NormalNC = {
    --                     guibg = "#262626",
    --                 },
    --             },
    --         }
    --     end,
    -- },

    {
        "folke/todo-comments.nvim",
        dependencies = { "nvim-lua/plenary.nvim" },
        opts = {
        }
    },

    {
        'phaazon/hop.nvim',
        branch = 'v2', -- optional but strongly recommended
        config = function()
            require 'hop'.setup { keys = 'etovxqpdygfblzhckisuran' }
        end
    },

    {
        "folke/trouble.nvim",
        dependencies = { "nvim-tree/nvim-web-devicons" },
        opts = {
        },
    },

}, {})

-------------------------------------------------------------------
-- LSP Configurations
-------------------------------------------------------------------
local on_attach = function(_, bufnr)
    local nmap = function(keys, func, desc)
        if desc then
            desc = 'LSP: ' .. desc
        end
        vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc })
    end

    nmap('<leader>rn', vim.lsp.buf.rename, 'Rename')
    nmap('<leader>ca', vim.lsp.buf.code_action, 'Code Action')
    nmap('gd', vim.lsp.buf.definition, 'Goto Definition')
    nmap('gD', vim.lsp.buf.declaration, 'Goto Declaration')
    nmap('gI', vim.lsp.buf.implementation, 'Goto Implementation')
    -- nmap('gr', require('telescope.builtin').lsp_references, 'Goto References')
    nmap('<leader>D', vim.lsp.buf.type_definition, 'Type Definition')
    nmap('K', vim.lsp.buf.hover, 'Hover Documentation')
    nmap('<C-k>', vim.lsp.buf.signature_help, 'Signature Documentation')
    -- nmap('<A-f>', vim.lsp.buf.format(), 'Format current buffer')
    -- nmap('<leader>ds', require('telescope.builtin').lsp_document_symbols, 'Document Symbols')
    -- nmap('<leader>ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Workspace Symbols')

    -- Create a command `:Format` local to the LSP buffer
    vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_)
        vim.lsp.buf.format()
    end, { desc = 'Format current buffer with LSP' })
end

-- Add LSP servers
local servers = {
    lua_ls = {
        Lua = {
            workspace = { checkThirdParty = false },
            telemetry = { enable = false },
        },
    },
    clangd = {
        cmd = { 'clangd', '--background-index' },
        filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
    },
    rust_analyzer = {},
    bashls = {},
    pyright = {},
    marksman = {},
}

-------------------------------------------------------------------
-- Plugin Setup
-------------------------------------------------------------------
-- nvim-cmp supports additional completion capabilities, so broadcast that to servers
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities)

-- Ensure the servers above are installed
local mason_lspconfig = require 'mason-lspconfig'

mason_lspconfig.setup {
    ensure_installed = vim.tbl_keys(servers),
}

mason_lspconfig.setup_handlers {
    function(server_name)
        require('lspconfig')[server_name].setup {
            capabilities = capabilities,
            on_attach = on_attach,
            settings = servers[server_name],
        }
    end,
}

local handlers = {
    ["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "solid" }),
    ["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "solid" }),
}

require('lspconfig').rust_analyzer.setup {
    on_attach = on_attach,
    handlers = handlers,
}

local opts = {
    tools = {
        runnables = {
            use_telescope = true,
        },
        inlay_hints = {
            auto = true,
            show_parameter_hints = false,
            parameter_hints_prefix = "=> ",
            other_hints_prefix = "=> ",
        },
    },

    -- all the opts to send to nvim-lspconfig
    -- these override the defaults set by rust-tools.nvim
    -- see https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#rust_analyzer
    server = {
        -- on_attach is a callback called when the language server attachs to the buffer
        on_attach = on_attach,
        settings = {
            -- to enable rust-analyzer settings visit:
            -- https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/generated_config.adoc
            ["rust-analyzer"] = {
                -- enable clippy on save
                checkOnSave = {
                    command = "clippy",
                },
            },
        },
    },
}

require("rust-tools").setup(opts)

require('lspconfig').clangd.setup {
    on_attach = on_attach,
    capabilities = { offsetEncoding = 'utf-16' },
    handlers = handlers,
}

local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, "lua/?.lua")
table.insert(runtime_path, "lua/?/init.lua")
require 'lspconfig'.lua_ls.setup {
    on_attach = on_attach,
    capabilities = capabilities,
    handlers = handlers,
    settings = {
        Lua = {
            runtime = {
                version = 'LuaJIT',
                path = runtime_path,
            },
            diagnostics = {
                globals = { 'vim' },
            },
            workspace = {
                library = vim.api.nvim_get_runtime_file("", true),
            },
            telemetry = {
                enable = false,
            },
        },
    },
}

-- Setup neovim lua configuration

-- [[ Configure nvim-cmp ]]
local cmp = require 'cmp'
local luasnip = require 'luasnip'
require('luasnip.loaders.from_vscode').lazy_load()
luasnip.config.setup {}
local cmp_opts = {
    border = "solid",
    winhighlight = 'Normal:Pmenu,FloatBorder:FloatBorder,Search:NONE,CursorLine:PmenuSel',
}
local has_words_before = function()
    if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then return false end
    local line, col = unpack(vim.api.nvim_win_get_cursor(0))
    return col ~= 0 and vim.api.nvim_buf_get_text(0, line - 1, 0, line - 1, col, {})[1]:match("^%s*$") == nil
end
cmp.setup {
    preselect = cmp.PreselectMode.None,
    view = {
        entries = "custom" -- can be "custom", "wildmenu" or "native"
    },
    completion = {
        completion = { completeopt = 'menu,menuone,noinsert,noselect' },
    },
    window = {
        completion = cmp.config.window.bordered(cmp_opts),
        documentation = cmp.config.window.bordered(cmp_opts),
    },
    snippet = {
        expand = function(args)
            luasnip.lsp_expand(args.body)
        end,
    },
    duplicates = {
        nvim_lsp = 1,
        luasnip = 1,
        cmp_tabnine = 1,
        buffer = 1,
        path = 1,
    },
    mapping = cmp.mapping.preset.insert {
        ['<C-Space>'] = cmp.mapping.complete {},
        ['<CR>'] = cmp.mapping.confirm {
            behavior = cmp.ConfirmBehavior.Replace,
            select = false,
        },
        ['<Tab>'] = cmp.mapping(function(fallback)
            if cmp.visible() and has_words_before() then
                cmp.select_next_item()
            elseif luasnip.expand_or_locally_jumpable() then
                luasnip.expand_or_jump()
            else
                fallback()
            end
        end, { 'i', 's' }),
        ['<S-Tab>'] = cmp.mapping(function(fallback)
            if cmp.visible() then
                cmp.select_prev_item()
            elseif luasnip.locally_jumpable(-1) then
                luasnip.jump(-1)
            else
                fallback()
            end
        end, { 'i', 's' }),
    },
    sources = {
        -- { name = 'copilot',  priority = 2 },
        { name = 'nvim_lsp', priority = 2 },
        { name = 'buffer',   priority = 2 },
        { name = 'path',     priority = 2 },
        { name = 'luasnip',  priority = 2 },
    },
}

cmp.setup.cmdline({ '/', '?' }, {
    mapping = cmp.mapping.preset.cmdline(),
    view = {
        entries = { name = 'wildmenu', separator = '|' }
    },
    window = {
        completion = cmp.config.window.bordered(cmp_opts),
        documentation = cmp.config.window.bordered(cmp_opts),
    },
    sources = {
        { name = 'buffer' }
    }
})

cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    view = {
        entries = { name = 'wildmenu', separator = '|' }
    },
    window = {
        completion = cmp.config.window.bordered(cmp_opts),
        documentation = cmp.config.window.bordered(cmp_opts),
    },
    sources = cmp.config.sources({
        { name = 'path' }
    }, {
        { name = 'cmdline' }
    })
})

-- [[ Configure Treesitter ]]
require('nvim-treesitter.configs').setup {
    -- Add languages to be installed here that you want installed for treesitter
    ensure_installed = { 'markdown_inline', 'markdown', 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'typescript', 'vimdoc', 'vim' },
    auto_install = true,

    highlight = { enable = true },
    indent = { enable = true },
    incremental_selection = {
        enable = true,
        keymaps = {
            init_selection = '<c-space>',
            node_incremental = '<c-space>',
            scope_incremental = '<c-s>',
            node_decremental = '<M-space>',
        },
    },
    textobjects = {
        select = {
            enable = true,
            lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
            keymaps = {
                -- You can use the capture groups defined in textobjects.scm
                ['aa'] = '@parameter.outer',
                ['ia'] = '@parameter.inner',
                ['af'] = '@function.outer',
                ['if'] = '@function.inner',
                ['ac'] = '@class.outer',
                ['ic'] = '@class.inner',
            },
        },
        move = {
            enable = true,
            set_jumps = true, -- whether to set jumps in the jumplist
            goto_next_start = {
                [']m'] = '@function.outer',
                [']]'] = '@class.outer',
            },
            goto_previous_start = {
                ['[m'] = '@function.outer',
                ['[['] = '@class.outer',
            },
            goto_next_end = {
                [']M'] = '@function.outer',
                [']['] = '@class.outer',
            },
            goto_previous_end = {
                ['[M'] = '@function.outer',
                ['[]'] = '@class.outer',
            },
        },
        swap = {
            enable = true,
            swap_next = {
                ['<leader>a'] = '@parameter.inner',
            },
            swap_previous = {
                ['<leader>A'] = '@parameter.inner',
            },
        },
    },
}

-- resizing splits
vim.keymap.set({ 'n', 't' }, '<A-h>', require('smart-splits').resize_left, { desc = 'Resize left' })
vim.keymap.set({ 'n', 't' }, '<A-j>', require('smart-splits').resize_down, { desc = 'Resize down' })
vim.keymap.set({ 'n', 't' }, '<A-k>', require('smart-splits').resize_up, { desc = 'Resize up' })
vim.keymap.set({ 'n', 't' }, '<A-l>', require('smart-splits').resize_right, { desc = 'Resize right' })
-- moving between splits
vim.keymap.set({ 'n', 't' }, '<C-h>', require('smart-splits').move_cursor_left, { desc = 'Move cursor left' })
vim.keymap.set({ 'n', 't' }, '<C-j>', require('smart-splits').move_cursor_down, { desc = 'Move cursor down' })
vim.keymap.set({ 'n', 't' }, '<C-k>', require('smart-splits').move_cursor_up, { desc = 'Move cursor up' })
vim.keymap.set({ 'n', 't' }, '<C-l>', require('smart-splits').move_cursor_right, { desc = 'Move cursor right' })
-- swapping buffers between windows
vim.keymap.set('n', '<leader><leader>h', require('smart-splits').swap_buf_left, { desc = 'Swap buffer left' })
vim.keymap.set('n', '<leader><leader>j', require('smart-splits').swap_buf_down, { desc = 'Swap buffer down' })
vim.keymap.set('n', '<leader><leader>k', require('smart-splits').swap_buf_up, { desc = 'Swap buffer up' })
vim.keymap.set('n', '<leader><leader>l', require('smart-splits').swap_buf_right, { desc = 'Swap buffer right' })
--Other
vim.keymap.set('n', 's', ":HopWord<cr>", { desc = 'hop', silent = true })
vim.keymap.set('n', '<tab>', ":tabNext<cr>", { desc = 'Next tab', silent = true })
vim.keymap.set('n', '<A-f>', ":Format<cr>", { desc = 'Format code', silent = true })
vim.keymap.set('n', '<C-m>', ":make<cr>", { desc = 'Format code', silent = true })
vim.keymap.set('n', '<C-n>', ":make clean<cr>", { desc = 'Format code', silent = true })
vim.keymap.set('n', '<C-s>', ":write<cr>", { desc = 'Save', silent = true })
vim.keymap.set('n', '<C-q>', ":quit<cr>", { desc = 'Quit', silent = true })
vim.keymap.set('n', '<leader>e', ":Neotree filesystem reveal float toggle<cr>", { desc = 'File explorer', silent = true })
vim.keymap.set('n', '<leader>d', ":Trouble diagnostics toggle<cr>", { desc = 'Diagnostic view', silent = true })
vim.keymap.set('n', '<leader>f', ":FzfLua files<cr>", { desc = 'Find file', silent = true })
