-- Load plugins
-- Bootstrap packer if needed {{
local fn = vim.fn
local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
if fn.empty(fn.glob(install_path)) > 0 then
  Packer_bootstrap = fn.system({'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim', install_path})
  vim.cmd [[packadd packer.nvim]]
end
-- }}

-- Reduce the maximum number of jobs in termux (a terminal for android) or if WEAK_SYSTEM is set to true
if (os.getenv("TERMUX_VERSION") ~= nil) or (os.getenv("WEAK_SYSTEM") == "true") then
   Packer_max_jobs = 5
else
   Packer_max_jobs = 100
end

local use = require('packer').use

return require('packer').startup({function()
   -- TODO: Find a better way to organize this

   -- impatient (needs to go early)
   use { -- lewis6991: impatient:      Make nvim load faster by caching them - needs to load early
      'lewis6991/impatient.nvim',
      config = function()
         require('impatient')
      end,
   }

   -- Packer
   use { -- packer:                    plugin manager
      'wbthomason/packer.nvim',
      config = function()
         -- Map :PS to :PackerSync
         vim.cmd 'cab PS PackerSync'
      end,
   }

   -- Colors (decorations)
   use { -- treesitter:                syntax highlighting and more
      'nvim-treesitter/nvim-treesitter',
      run = ':TSUpdate',
      config = function()
         require('blake.lsp').treesitter()
      end,
   }
   use { -- onedark.nvim:              onedark theme
      'navarasu/onedark.nvim',
      config = function()
         -- vim.g.onedark_transparent_background = true
         vim.cmd [[
            "au ColorScheme onedark hi TabLine gui=none guibg='#282C34' guifg='#5C6370'  " all tabs color
            au ColorScheme onedark hi TabLineSel       guibg='#282C34' guifg='#B5BBC7'  " Highlighted tab color
            "au ColorScheme onedark hi TabLineFill      guibg='#282C34'                  " tabline portion without tabs (right-hand side)
         ]]
      end
   }
   use { -- tokyonight.nvim:           tokyonight theme
      'folke/tokyonight.nvim',
      config = function()
         -- vim.g.tokyonight_style = "night"
         vim.g.tokyonight_italic_functions = true
         vim.g.tokyonight_sidebars = { "nvimtree", "qf", "vista_kind", "terminal", "packer" }
         vim.cmd [[
            au ColorScheme tokyonight hi TabLine gui=none guibg='#1D202F' guifg='#565F89'  " all tabs color
            au ColorScheme tokyonight hi TabLineSel       guibg='#24283B' guifg='#C0CAF5'  " Highlighted tab color
            au ColorScheme tokyonight hi TabLineFill      guibg='#1D202F'                  " tabline portion without tabs (right-hand side)
         ]]
         -- Has to be put here so it runs synchronously
         vim.cmd 'colorscheme tokyonight'
      end,
   }
   use { -- newspring:                 Good light theme for writing
      'NLKNguyen/papercolor-theme',
   }
   use { -- statusline:                lualine
      'nvim-lualine/lualine.nvim',
      requires = { 'kyazdani42/nvim-web-devicons', opt = true },
      config = function()
         require('blake.other').lualine()
      end,
   }
   use { -- nvim-tabline:              batter looking tabline
      'alvarosevilla95/luatab.nvim',
      requires = { 'kyazdani42/nvim-web-devicons' },
      config = function()
         require('luatab').setup()
      end
   }
   use { -- nvim-colorizer:            css color tag highlighter (ex- #FFB13B)
      'norcalli/nvim-colorizer.lua',
      config = function()
         vim.cmd 'cab COL ColorizerToggle'
      end,
   }
   use { -- vim-illuminate:            highlight other occurrences of the word under cursor
      'RRethy/vim-illuminate',
      -- commit = '27f6ef135a88d9410a33cf92fc47f5c018df552c', -- for finding the correct color to make highlights
      config = function()
         vim.keymap.set('n', '<a-i>', require('illuminate').toggle_freeze_buf)
         vim.api.nvim_set_hl(0, "IlluminatedWordText",  { bg = "#3b4261" })
         vim.api.nvim_set_hl(0, "IlluminatedWordRead",  { bg = "#3b4261" })
         vim.api.nvim_set_hl(0, "IlluminatedWordWrite", { bg = "#3b4261" })
         require('illuminate').configure({
            providers = {
               'treesitter',
               'regex',
            }
         })
      end
   }

   -- IDE features
   ---- LSP
   use { -- lspinstall:                language server installer, (lspconfig is here too)
      'williamboman/nvim-lsp-installer',
      { -- lspconfig: default language server configurations
         'neovim/nvim-lspconfig',
         config = function()
            require('blake.lsp').lspinstall()
            require('blake.lsp').lspconfig()
         end
      }
   }
   use { -- rust-tools:                make nvim a better rust environment
      'simrat39/rust-tools.nvim',
      requires = {
         'mattn/webapi-vim',  -- allow :RustPlay
      },
      config = function ()
         local rt = require("rust-tools")
         rt.setup({
            server = {
               on_attach = function(_, bufnr)
                  -- Hover actions
                  vim.keymap.set("n", "K", rt.hover_actions.hover_actions, { buffer = bufnr })
                  -- Code action groups
                  vim.keymap.set("n", "<Leader>a", rt.code_action_group.code_action_group, { buffer = bufnr })
               end,
            },
         })
      end
   }
   use { -- cmp:                       completion menu
      'hrsh7th/nvim-cmp',
      config = function()
         require('blake.lsp').cmp()
      end,
      requires = { -- (mostly) nvim-cmp sources (not required by cmp, but reqired by my configuration)
         'onsails/lspkind-nvim', -- icons for entries of the completion menu, required by config
         'hrsh7th/cmp-path',
         'hrsh7th/cmp-nvim-lua',
         'hrsh7th/cmp-nvim-lsp',
         'saadparwaiz1/cmp_luasnip',
         'ray-x/cmp-treesitter',
         'hrsh7th/cmp-calc',
         'f3fora/cmp-spell',
         'hrsh7th/cmp-buffer',
         'hrsh7th/cmp-cmdline',
         'hrsh7th/cmp-emoji',
      },
   }
   use { -- luasnip:                   snippits plugin
      'L3MON4D3/LuaSnip',
      config = function()
         require("luasnip.loaders.from_vscode").lazy_load()
      end
   }
   use { -- friendly-snippets:         lots of good snippits
      'rafamadriz/friendly-snippets'
   }
   use { -- lsp_signature:             function parameter previews
      'ray-x/lsp_signature.nvim',
      after = 'nvim-lspconfig',
      config = function()
         require('blake.lsp').signature()
      end,
   }
   use { -- symbols-outline:           treesitter-based document outline (SO)
      'simrat39/symbols-outline.nvim',
      config = function()
         vim.cmd 'cab SO SymbolsOutline'
         vim.cmd 'nnoremap <Leader>so <cmd>SymbolsOutline<CR>'
      end,
   }
   use { -- null-ls:                   Support for lots of programming tools, but through nvim lsp
      'jose-elias-alvarez/null-ls.nvim',
      requires = { 'nvim-lua/plenary.nvim' },
      config = function()
         local null_ls = require("null-ls")
         require("null-ls").setup({
            sources = {
               null_ls.builtins.code_actions.refactoring,
               null_ls.builtins.formatting.jq,
            }
         })
      end
   }
   use { -- refactoring:               Refactoring tools for neovim
      'ThePrimeagen/refactoring.nvim',
      requires = {
         { 'nvim-lua/plenary.nvim' },
         { 'nvim-treesitter/nvim-treesitter' }
      },
      config = function()
         require('refactoring').setup({})
         -- Remaps for the refactoring operations currently offered by the plugin
         vim.api.nvim_set_keymap("v", "<leader>re", [[ <Esc><Cmd>lua require('refactoring').refactor('Extract Function')<CR>]], {noremap = true, silent = true, expr = false})
         vim.api.nvim_set_keymap("v", "<leader>rf", [[ <Esc><Cmd>lua require('refactoring').refactor('Extract Function To File')<CR>]], {noremap = true, silent = true, expr = false})
         vim.api.nvim_set_keymap("v", "<leader>rv", [[ <Esc><Cmd>lua require('refactoring').refactor('Extract Variable')<CR>]], {noremap = true, silent = true, expr = false})
         vim.api.nvim_set_keymap("v", "<leader>ri", [[ <Esc><Cmd>lua require('refactoring').refactor('Inline Variable')<CR>]], {noremap = true, silent = true, expr = false})
         -- Extract block doesn't need visual mode
         vim.api.nvim_set_keymap("n", "<leader>rb", [[ <Cmd>lua require('refactoring').refactor('Extract Block')<CR>]], {noremap = true, silent = true, expr = false})
         vim.api.nvim_set_keymap("n", "<leader>rbf", [[ <Cmd>lua require('refactoring').refactor('Extract Block To File')<CR>]], {noremap = true, silent = true, expr = false})
         -- Inline variable can also pick up the identifier currently under the cursor without visual mode
         vim.api.nvim_set_keymap("n", "<leader>ri", [[ <Cmd>lua require('refactoring').refactor('Inline Variable')<CR>]], {noremap = true, silent = true, expr = false})
         -- Refactoring telescope integration
         -- load refactoring Telescope extension
         require("telescope").load_extension("refactoring")
         -- remap to open the Telescope refactoring menu in visual mode
         vim.api.nvim_set_keymap(
            "v",
            "<leader>rr",
            "<Esc><cmd>lua require('telescope').extensions.refactoring.refactors()<CR>",
            { noremap = true }
         )
      end,
   }

   ---- DAP (Debug Adapter Protocol)
   use { -- nvim-dap:                  DAP support
      'mfussenegger/nvim-dap',
      config = function()
         require('blake.dap').nvim_dap()
      end
   }
   -- use { -- dap-buddy:              DAP adapter installer - DBInstall
   --    'Pocco81/dap-buddy.nvim',
   --    config = function()
   --       require('blake.dap').dap_buddy()
   --    end
   -- }
   use { -- virtual-text:              Print Variable names while debugging
      'theHamsta/nvim-dap-virtual-text',
      config = function()
         -- calling this with a parameter to keep lua language server from complaining
         require("nvim-dap-virtual-text").setup({context_commentstring = {enable = true,}})
      end
   }
   use { -- nvim-dap-ui:               a UI for nvim-dap
      'rcarriga/nvim-dap-ui',
      requires = { 'mfussenegger/nvim-dap' },
      config = function()
         require('blake.dap').dap_ui()
      end,
   }
   use { -- debugprint:                automatic debug print statement creator - bind g?{p/P,v/V,o/O}
      'andrewferrier/debugprint.nvim',
      requires = { 'nvim-treesitter/nvim-treesitter' },
      config = function()
         require('debugprint').setup()
      end
   }

   ---- Other IDE features
   use { -- telescope:                 fuzzy finder for finding fuzzy things
      'nvim-telescope/telescope.nvim',
      requires = { 'nvim-lua/plenary.nvim' },
      config = function()
         require('blake.other').telescope()
      end
   }
   use { -- trouble:                   one big list of code errors from all sources (lsp, quickfix)
      'folke/trouble.nvim',
      requires = "kyazdani42/nvim-web-devicons",
      config = function()
         require('trouble').setup({ mode = "quickfix" })
      end
   }
   use { -- bqf:                       improved quickfix list
      'kevinhwang91/nvim-bqf',
      ft = 'qf',
   }
   use { -- pqf:                       prettier quickfix list
      'https://gitlab.com/yorickpeterse/nvim-pqf',
      ft = 'qf',
   }
   use { -- gitsigns:                  git integration
      'lewis6991/gitsigns.nvim',
      requires = { 'nvim-lua/plenary.nvim' },
      config = function()
         require('blake.other').gitsigns()
      end,
   }
   use { -- toggleterm:                terminal
      'akinsho/toggleterm.nvim',
      branch = 'main',
      config = function()
         require('blake.other').toggleterm()
      end
   }
   use { -- neoscroll:                 Smooth Scrolling
      'karb94/neoscroll.nvim',
      disable = true,
      config = function()
         require('blake.other').neoscroll()
      end,
   }
   use { -- auto-session:              automatic session management
      'rmagatti/auto-session',
      config = function()
         require('blake.other').autosession()
      end
   }
   use { -- glow:                      Markdown preview
      'ellisonleao/glow.nvim',
      ft = { 'md', 'markdown', }
   }
   use { -- zen mode:                  (ZenMode or ZM)
      "folke/zen-mode.nvim",
      config = function()
         require('blake.other').zenmode()
         vim.cmd 'nnoremap <F10> <cmd>ZenMode<CR>'
         vim.cmd 'inoremap <F10> <cmd>ZenMode<CR>'
      end,
   }
   -- use { -- twilight.nvim:          dim text outside paragraph or function
   --    'folke/twilight.nvim',
   --    config = function()
   --       vim.cmd 'cab TW Twilight'
   --       require("twilight").setup()
   --    end,
   -- }
   use { -- matchup:                   Use the percent (%) key for more things
      'andymass/vim-matchup',
   }
   use { -- indentline:                Line indent indicators
      'lukas-reineke/indent-blankline.nvim',
      config = function()
         require('blake.other').indent_blankline()
      end
   }
   use { -- targets.vim:               fix ci' and other things to work better
      'wellle/targets.vim',
   }
   use { -- nvim-tree:                 File explorer
      'kyazdani42/nvim-tree.lua',
      requires = { 'kyazdani42/nvim-web-devicons' },
      tag = 'nightly',
      config = function()
         require("nvim-tree").setup({
            diagnostics = { enable = true, },
         })
      end
   }
   use { -- neogen:                    annotation generator for neovim
      'danymat/neogen',
      requires = "nvim-treesitter/nvim-treesitter",
      config = function()
         require('neogen').setup({
            snippet_engine = "luasnip",
         })
         local opts = { noremap = true, silent = true }
         vim.api.nvim_set_keymap("n", "<Leader>af", ":lua require('neogen').generate('func')<CR>", opts)
      end
   }
   use { -- hop.nvim:                  Jump around files quickly
      'phaazon/hop.nvim',
      config = function()
         require('hop').setup { keys = 'etovxqpdygfblzhckisuran' }
      end
   }

   -- Conveniences
   use { -- sort motion:               (gs)
      'christoomey/vim-sort-motion',
      requires = 'navicore/vissort.vim', -- config requires
      config = function()
         vim.cmd [[
            "let g:sort_motion_flags = 'i'
            let g:sort_motion_visual_block_command = 'Vissort'
         ]]
      end,
   }
   use { -- vissort:                   "Visual Sort" - sort based on selected characters
      'navicore/vissort.vim',
      cmd = 'Vissort',
   }
   use { -- ghost:                     Web browser integration
      'raghur/vim-ghost',
      opt = true,
      cmd = {'GhostStart', 'GhostInstall', 'GhostStop', 'GhostSync', 'GhostToggleSync',},
   }
   use { -- undotree:                  visual undo tree
      'mbbill/undotree',
      config = function()
         vim.api.nvim_set_keymap('n', '<Leader>u', '<cmd>UndotreeToggle<CR>', { noremap = true, silent = true, })
      end
   }
   use { -- macroeditor:               edit macros in another window to avoid making LSP mad
      'dohsimpson/vim-macroeditor',
      config = function()
         vim.cmd 'cab ME MacroEdit'
      end
   }
  --  use { -- shade.nvim:             dim inactive window
  --    'sunjon/shade.nvim',
  --    config = function()
  --       require'shade'.setup({
  --          overlay_opacity = 50,
  --          opacity_step = 1,
  --          keys = {
  --             brightness_up    = '<C-Up>',
  --             brightness_down  = '<C-Down>',
  --             toggle           = '<Leader>s',
  --          }
  --       })
  --    end
  -- }
   use { -- nvim-autopairs:            automatic quote pairing
      'windwp/nvim-autopairs',
      config = function()
         -- If you want insert `(` after select function or method item
         local cmp_autopairs = require('nvim-autopairs.completion.cmp')
         local cmp = require('cmp')
         cmp.event:on(
            'confirm_done',
            cmp_autopairs.on_confirm_done()
         )
         require('nvim-autopairs').setup({
            check_ts = true,
            map_c_h = true,
            map_c_w = true,
         })
      end,
      requires = { 'hrsh7th/nvim-cmp' }, -- config requires
   }
   use { -- ts-autotag:                automatically close html tags
      'windwp/nvim-ts-autotag',
      config = function()
         require('nvim-ts-autotag').setup()
      end
   }
   use { -- endwise:                   auto add 'end' keyword when typing loops in various languages
   'RRethy/nvim-treesitter-endwise',
   config = function()
      require('nvim-treesitter.configs').setup {
         endwise = {
            enable = true,
         },
      }
   end
}
   use { -- nvim-align:                Align text
      'RRethy/nvim-align',
   }
   use { -- comment.nvim:              toggle comments - gb and gc
      'numToStr/Comment.nvim',
      config = function()
         require('Comment').setup {
            mappings = {
               extra = true,
            }
         }
      end
   }
   use { -- ts-context-commentstring:  set commentstring based on context from treesitter (two langs in one file)
      'JoosepAlviste/nvim-ts-context-commentstring',
      requires = { 'nvim-treesitter/nvim-treesitter' },
      config = function()
         require'nvim-treesitter.configs'.setup {
            context_commentstring = {
               enable = true,
               enable_autocmd = false,
            },
         }
      end,
   }
   use { -- filetype.nvim:             detect filetype a lot faster than stock neovim
      'nathom/filetype.nvim',
   }
   use { -- vim-rooter:                cd to the root of a project when opening a file or folder
      'notjedi/nvim-rooter.lua',
   }
   use { -- splitjoin:                 switch between single line and multiline versions of code - gJ and gS
      'AndrewRadev/splitjoin.vim',
   }
   use { -- which-key:                 remind me what that one keybind does again?
      'folke/which-key.nvim',
      config = function()
         require("which-key").setup()
      end,
   }
   use { -- marks.nvim:                Show marks in sign column
      'chentoast/marks.nvim',
      config = function()
         require('marks').setup()
      end
   }
   use { -- oscyank:                   copy text to system clipboard over ssh
      'ojroques/vim-oscyank',
      config = function()
         -- Yanking to "+ will yank to system board
         vim.cmd [[ autocmd TextYankPost * if v:event.operator is 'y' && v:event.regname is '+' | execute 'OSCYankReg +' | endif ]]
      end
   }
   use { -- fixcursorhold:             fix neovim bug #12587 - https://github.com/neovim/neovim/issues/12587
      'antoinemadec/FixCursorHold.nvim',
   }
   use { -- rhysd: clever-split:       split calculation based on pane dimensions - CS or CleverSplit
      'rhysd/clever-split.vim',
      config = function()
         vim.cmd [[
         cab CH CleverHelp
         cab CS CleverSplit
         ]]
      end
   }
   -- use { -- rhysd: accelerated jk:  make j and k move faster by pressing them a lot movement
   --    'rhysd/accelerated-jk',
   -- }
   use { -- rhysd: committia:          better commit editing window
      'rhysd/committia.vim',
   }
   use { -- rhysd: conflict-marker:    mark git conflicts - [x, ]x, co, ct, cb, cB, cn
      'rhysd/conflict-marker.vim',
   }
   use { -- lewis6991: spellsitter:    Spell checking in treesitter files
      'lewis6991/spellsitter.nvim',
      config = function()
         require('spellsitter').setup()
      end,
   }
   use { -- lewis6991: spaceless:      Strip trailing whitespace as you are editing
      'lewis6991/spaceless.nvim',
      config = function()
         require'spaceless'.setup()
      end,
   }
   use { -- lewis6991: foldsigns:      signcolumn signs on folded lines
      'lewis6991/foldsigns.nvim',
      config = function()
         require('foldsigns').setup()
      end,
   }
   use { -- lewis6991: cleanfold:      folds have never looked better
      'lewis6991/cleanfold.nvim',
      config = function()
         require('cleanfold').setup()
      end,
   }
   -- use { -- lewis6991: sattelite:   small scroll bar
   --    'lewis6991/satellite.nvim',
   --    config = function()
   --       require('satellite').setup()
   --       vim.cmd [[
   --          nnoremap <C-l> <cmd>nohlsearch\|diffupdate\|SatelliteRefresh<CR>
   --          inoremap <C-l> <cmd>nohlsearch\|diffupdate\|SatelliteRefresh<CR>
   --       ]]
   --    end,
   -- }
   use { -- tpope: surround:           surround text with quotes, parens, tags, and more - ys
      'tpope/vim-surround',
   }
   use { -- tpope: fugitive:           git integration
      'tpope/vim-fugitive',
      cmd = 'G',
   }
   use { -- tpope: repeat:             Repeatability for various tpope plugins
      'tpope/vim-repeat',
   }
   use { -- tpope: sleuth:             automatically get info about files and apply it to vim (tabs vs spaces, etc)
      'tpope/vim-sleuth',
   }
   use { -- tpope: eunuch:             some unix shell commands in vim
      'tpope/vim-eunuch',
      cmd = { 'Remove', 'Unlink', 'Delete', 'Copy', 'Duplicate', 'Move', 'Rename', 'Chmod', 'Mkdir', 'Mkdir', 'Cfind', 'Lfind', 'Clocate', 'Llocate', 'SudoEdit', 'SudoWrite', },
   }

   -- Bootstrap packer if needed {
   if (Packer_bootstrap) then
      print('Please wait for packer to install plugins')
      require('packer').sync()
   end
   -- }
end,
config = {
   -- Make packer a floating window with single border
   display = {
      open_fn = function()
         return require('packer.util').float({ border = 'single' })
      end
   },
   -- Move to lua dir so impatient.nvim can cache it
   compile_path = vim.fn.stdpath('config')..'/lua/packer_compiled.lua',
   -- Don't ask before removing plugins
   autoremove = true,
   -- Limit max jobs to avoid getting killed on low-end hardware
   max_jobs = Packer_max_jobs,
   profile = {
      enable = true,
   },
}})

-- how to align all plugin descriptions: select all plugins in visual line, :'<,'>Align \(.\+use { -- .\+: \+\)\@<=[^ ][^:]\+$

-- vim:fdm=marker:fmr={,}:fdl=1:expandtab:tabstop=3:sw=3