return {
  'hrsh7th/nvim-cmp',
  ft = { 'lua', 'rust', 'python' },
  dependencies = {
    'hrsh7th/cmp-nvim-lsp',
    'hrsh7th/cmp-nvim-lua',
    'hrsh7th/cmp-path',
    'hrsh7th/cmp-buffer',
    'hrsh7th/cmp-cmdline',
    'saadparwaiz1/cmp_luasnip',
    'onsails/lspkind.nvim',
  },
  config = function()
    local cmp = require 'cmp'
    local luasnip = require 'luasnip'

    cmp.setup {
      enabled = function()
        if
          vim.api.nvim_buf_get_option(0, 'buftype') == 'prompt'
          or require('cmp.config.context').in_syntax_group 'Comment'
        then
          return false
        else
          return true
        end
      end,
      snippet = {
        expand = function(args)
          luasnip.lsp_expand(args.body)
        end,
      },
      mapping = cmp.mapping.preset.insert {
        ['<C-d>'] = cmp.mapping.scroll_docs(-1),
        ['<C-f>'] = cmp.mapping.scroll_docs(1),
        ['<C-Space>'] = cmp.mapping(function(_)
          return vim.fn.pumvisible() == 1 and cmp.close() or cmp.complete()
        end),
        ['<C-e>'] = cmp.mapping {
          i = cmp.mapping.abort(),
          c = cmp.mapping.close(),
        },
        ['<CR>'] = cmp.mapping {
          i = function(fallback)
            if cmp.visible() and cmp.get_active_entry() then
              cmp.confirm { behavior = cmp.ConfirmBehavior.Replace, select = false }
            else
              fallback()
            end
          end,
          s = cmp.mapping.confirm { select = true },
        },
        ['<Tab>'] = cmp.mapping(function(fallback)
          if cmp.visible() then
            cmp.select_next_item()
          elseif luasnip.expand_or_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.jumpable(-1) then
            luasnip.jump(-1)
          else
            fallback()
          end
        end, { 'i', 's' }),
      },
      window = {
        documentation = {
          border = { '┌', '─', '┐', '│', '┘', '─', '└', '│' },
          winhighlight = 'Normal:CmpPmenu,FloatBorder:CmpPmenuBorder,CursorLine:PmenuSel,Search:None',
          side_padding = 1,
        },
        completion = {
          winhighlight = 'Normal:Pmenu,FloatBorder:Pmenu,Search:None',
          col_offset = -3,
          side_padding = 0,
          scrollbar = '║',
        },
      },
      view = {
        entries = 'bordered',
      },
      experimental = { ghost_text = true },
      formatting = {
        fields = { 'kind', 'abbr', 'menu' },
        format = function(entry, vim_item)
          local kind =
            require('lspkind').cmp_format { maxwidth = 50, preset = 'codicons', mode = 'symbol_text' }(entry, vim_item)
          local strings = vim.split(kind.kind, '%s', { trimempty = true })
          kind.kind = ' ' .. strings[1] .. ' '
          kind.menu = '    (' .. strings[2] .. ')'
          return kind
        end,
      },
      sources = cmp.config.sources({
        { name = 'luasnip', max_item_count = 10, group_index = 1 },
        { name = 'nvim_lsp', max_item_count = 20, group_index = 1 },
        { name = 'nvim_lua', group_index = 1 },
      }, {
        { name = 'path', group_index = 2 },
        { name = 'buffer', keyword_length = 2, max_item_count = 5, group_index = 2 },
      }),
    }

    local presentAutopairs, cmp_autopairs = pcall(require, 'nvim-autopairs.completion.cmp')
    if not presentAutopairs then
      return
    end
    cmp.event:on('confirm_done', cmp_autopairs.on_confirm_done { map_char = { tex = '' } })

    cmp.setup.cmdline(':', {
      mapping = cmp.mapping.preset.cmdline(),
      sources = cmp.config.sources({
        { name = 'path' },
      }, {
        {
          name = 'cmdline',
          option = {
            ignore_cmds = { 'Man', '!' },
          },
        },
      }),
    })
  end,
}
