[
  {
    "path": "README.md",
    "content": "# cmp-nvim-lsp-document-symbol\n\nnvim-cmp source for textDocument/documentSymbol via nvim-lsp.\n\nThe purpose is the demonstration customize `/` search by nvim-cmp.\n\n<video src=\"https://user-images.githubusercontent.com/629908/139110682-b88e5e1f-f46f-4663-b92e-28b0007f9e52.mp4\" width=\"100%\"></video>\n\n# Setup\n\n```lua\nrequire'cmp'.setup.cmdline('/', {\n  sources = cmp.config.sources({\n    { name = 'nvim_lsp_document_symbol' }\n  }, {\n    { name = 'buffer' }\n  })\n})\n```\n\n"
  },
  {
    "path": "after/plugin/cmp_nvim_lsp_document_symbol.lua",
    "content": "require('cmp').register_source('nvim_lsp_document_symbol', require('cmp_nvim_lsp_document_symbol').new())\n"
  },
  {
    "path": "lua/cmp_nvim_lsp_document_symbol/init.lua",
    "content": "local source = {}\n\nlocal SymbolKind = {\n  [1] = 'File',\n  [2] = 'Module',\n  [3] = 'Namespace',\n  [4] = 'Package',\n  [5] = 'Class',\n  [6] = 'Method',\n  [7] = 'Property',\n  [8] = 'Field',\n  [9] = 'Constructor',\n  [10] = 'Enum',\n  [11] = 'Interface',\n  [12] = 'Function',\n  [13] = 'Variable',\n  [14] = 'Constant',\n  [15] = 'String',\n  [16] = 'Number',\n  [17] = 'Boolean',\n  [18] = 'Array',\n  [19] = 'Object',\n  [20] = 'Key',\n  [21] = 'Null',\n  [22] = 'EnumMember',\n  [23] = 'Struct',\n  [24] = 'Event',\n  [25] = 'Operator',\n  [26] = 'TypeParameter',\n}\n\nsource.new = function()\n  return setmetatable({}, { __index = source })\nend\n\nsource.is_available = function(self)\n  return self:_get_client() ~= nil\nend\n\nsource.get_keyword_pattern = function()\n  return [=[@.*]=]\nend\n\nsource.get_trigger_characters = function()\n  return { '@' }\nend\n\nsource.complete = function(self, _, callback)\n  local client = self:_get_client()\n  client.request('textDocument/documentSymbol', { textDocument = vim.lsp.util.make_text_document_params() }, function(err, res)\n    if err then\n      return callback()\n    end\n\n    local items = {}\n    local traverse\n    traverse = function(nodes, level)\n      level = level or 0\n      for _, node in ipairs(nodes) do\n        local kind_name = SymbolKind[node.kind]\n        if vim.tbl_contains({ 'Module', 'Namespace', 'Object', 'Class', 'Interface', 'Method', 'Function' }, kind_name) then\n          -- node may be LSP DocumentSymbol or SymbolInformation (deprecated)\n          local range = node.selectionRange or node.range or (node.location or {}).range\n          if range ~= nil then\n            local line = vim.api.nvim_buf_get_lines(0, range.start.line, range.start.line + 1, false)[1] or ''\n            table.insert(items, {\n              label = ('%s%s'):format(string.rep(' ', level), string.gsub(line, '^%s*', '')),\n              insertText = ('\\\\%%%sl'):format(range.start.line + 1),\n              filterText = '@' .. node.name,\n              sortText = '' .. range.start.line,\n              kind = node.kind,\n              data = node,\n            })\n            traverse(node.children or {}, level + 1)\n          end\n        end\n      end\n    end\n    traverse(res or {})\n    callback(items)\n  end)\nend\n\nsource._get_client = function(self)\n  for _, client in pairs(vim.lsp.get_clients({ bufnr = 0 })) do\n    if self:_get(client.server_capabilities, { 'documentSymbolProvider' }) then\n      return client\n    end\n  end\n  return nil\nend\n\nsource._get = function(_, root, paths)\n  local c = root\n  for _, path in ipairs(paths) do\n    c = c[path]\n    if not c then\n      return nil\n    end\n  end\n  return c\nend\n\nreturn source\n"
  }
]