Skip to content

Instantly share code, notes, and snippets.

@dmlary
Last active July 13, 2023 16:25
Show Gist options
  • Save dmlary/f948318ee40d667cbde2e0cf938cc3bb to your computer and use it in GitHub Desktop.
Save dmlary/f948318ee40d667cbde2e0cf938cc3bb to your computer and use it in GitHub Desktop.
neovim cscope telescope integration
--[[
Navigate cscope in neovim using telescope with multiple databases
Setup:
local cscope = require('cscope')
-- look for cscope.out in the current working directory
cscope.add_database { path = "." }
-- add a second database and set the top-level path for files in that db
cscope.add_database {
path = "/project/altitude/src",
db = "/project/altitude/cscope-src.out",
}
Usage:
User commands: CscopeFind<Type>
Mappings: <Leader>c<Type>
--]]
local pickers = require "telescope.pickers"
local finders = require "telescope.finders"
local conf = require("telescope.config").values
local M = {
databases = {},
}
local cscope_find = function(db, path, type, query, results)
local type_flags = {
a = "-9",
c = "-3",
d = "-2",
e = "-6",
f = "-7",
g = "-1",
i = "-8",
s = "-0",
t = "-4",
}
local type_flag = type_flags[type]
assert(type_flag)
local cmd = string.format("cscope -dL -f %s %s '%s'", db, type_flag, query)
-- print(cmd)
local file = assert(io.popen(cmd, "r"))
file:flush()
local output = file:read("*all")
file:close()
for line in output:gmatch("([^\n]*)\n?") do
file, func, lnum, buf = string.match(line, "(%S+) (%S+) (%d+)%s*(.*)")
if file ~= nil then
table.insert(results, {
path = path .. "/" .. file,
file = file,
func = func,
lnum = tonumber(lnum),
buf = buf
})
end
end
return results
end
M.cscope = function(type, query, opts)
local results = {};
for _, db in ipairs(M.databases) do
cscope_find(db.db, db.path, type, query, results)
end
opts = opts or {}
pickers.new(opts, {
prompt_title = "cscope results",
finder = finders.new_table {
results = results,
entry_maker = function(entry)
return {
value = entry.file,
path = entry.path,
lnum = entry.lnum,
display = string.format("%s:%d:%s %s",
entry.file, entry.lnum, entry.func, entry.buf),
ordinal = string.format("%s:%d:%s %s",
entry.file, entry.lnum, entry.func, entry.buf),
}
end
},
sorter = conf.generic_sorter(opts),
previewer = conf.grep_previewer(opts),
}):find()
end
-- add a new database to the list
M.add_database = function(args)
if args.path == nil then
error("must provide a path; the directory containing files in cscope db")
return
end
if args.db == nil then
args.db = args.path .. "/cscope.out"
end
table.insert(M.databases, args)
end
-- clear the database list
M.clear_databases = function()
M.databases = {}
end
-- [[ define commands ]]
local commands = {
Assignments = "a",
Callers = "c",
Called = "d",
Egrep = "e",
File = "f",
Global = "g",
Include = "i",
Symbol = "s",
TextString = "t"
}
for name, arg in pairs(commands) do
local command = "CscopeFind" .. name
vim.api.nvim_create_user_command(command,
function(opts)
M.cscope(arg, opts.fargs[1])
end,
{ nargs = 1 })
end
vim.api.nvim_create_user_command('CscopeShowDatabases',
function()
print(vim.inspect(M.databases))
end,
{})
-- [[ mappings ]]
for name, arg in pairs(commands) do
vim.keymap.set("n", "<leader>c" .. arg,
function()
M.cscope(arg, vim.fn.expand("<cword>"))
end,
{ desc = "cscope find " .. string.lower(name), })
vim.keymap.set("n", "<leader>c" .. string.upper(arg),
":CscopeFind" .. name .. " ",
{ desc = "cscope find " .. name .. " ...", })
end
return M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment