Move build.lua to plugin directory
This commit is contained in:
168
plugin/build.lua
Normal file
168
plugin/build.lua
Normal file
@@ -0,0 +1,168 @@
|
||||
local build = {}
|
||||
|
||||
build.dir = nil
|
||||
|
||||
local function echo(message, highlight)
|
||||
vim.api.nvim_echo({ { message, highlight }, }, true, {})
|
||||
end
|
||||
|
||||
function build.set_dir(dirname)
|
||||
if not dirname then
|
||||
build.select_dir()
|
||||
return
|
||||
end
|
||||
local current_dir = vim.fn.getcwd()
|
||||
local build_dir = current_dir .. '/' .. dirname
|
||||
-- print(build_dir)
|
||||
|
||||
if vim.fn.isdirectory(build_dir) == 0 then
|
||||
echo('directory does not exist: ' .. build_dir, 'Error')
|
||||
return
|
||||
end
|
||||
|
||||
build.dir = build_dir
|
||||
|
||||
echo('Processing compile_commands.json with compdb ...', 'DiagnosticInfo')
|
||||
local compile_commands = current_dir .. '/compile_commands.json'
|
||||
-- Post-process compile_commands.json with compdb as an async job to avoid
|
||||
-- blocking the user interface
|
||||
vim.fn.jobstart(
|
||||
'compdb -p ' .. build.dir .. ' list > ' .. compile_commands, {
|
||||
|
||||
-- Restart clangd language server
|
||||
-- TODO: Configure cmake language server?
|
||||
on_exit = function()
|
||||
vim.cmd.LspRestart('clangd')
|
||||
echo('Build directory selected: ' .. dirname, 'DiagnosticInfo')
|
||||
end,
|
||||
|
||||
-- Display any error messages to the user
|
||||
on_stderr = function(_, output, _)
|
||||
-- Remove any lines containing a compdb warning
|
||||
local error = {}
|
||||
local warning = 'WARNING:compdb'
|
||||
for _, line in ipairs(output) do
|
||||
if string.sub(line, 1, #warning) ~= warning then
|
||||
table.insert(error, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- Display the error message if there was one
|
||||
if table.maxn(error) > 0 then
|
||||
echo(vim.fn.join(error, '\n'), 'Error')
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
stderr_buffered = true,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
function build.select_dir(callback)
|
||||
local dirs = build.list_dirs()
|
||||
callback = callback or nil
|
||||
|
||||
if table.maxn(dirs) == 1 then
|
||||
build.set_dir(dirs[1])
|
||||
return
|
||||
end
|
||||
|
||||
if vim.fn.exists(':Telescope') > 0 then
|
||||
-- Create a Telescope picker with custom action.
|
||||
require('telescope.pickers').new({}, {
|
||||
prompt_title = 'Select build directory',
|
||||
finder = require('telescope.finders').new_table({ results = dirs }),
|
||||
sorter = require("telescope.config").values.generic_sorter({}),
|
||||
attach_mappings = function(bufnr, map)
|
||||
-- Override the default confirm action
|
||||
map('i', '<CR>', function()
|
||||
-- Get the select build directory
|
||||
local state = require('telescope.actions.state')
|
||||
build.set_dir(state.get_selected_entry().value)
|
||||
-- Close the Telescope floating window
|
||||
require('telescope.actions').close(bufnr)
|
||||
-- Invoke the callback if provided
|
||||
if callback then callback() end
|
||||
end)
|
||||
return true
|
||||
end,
|
||||
layout_config = {
|
||||
height = function(_, _, max_lines)
|
||||
-- Limit the height based on the number of dirs
|
||||
return math.min(max_lines, table.maxn(dirs) + 5)
|
||||
end
|
||||
}
|
||||
}):find()
|
||||
else
|
||||
-- Prompt user to choose dir with to inputlist
|
||||
local choices = {}
|
||||
for index, choice in ipairs(dirs) do
|
||||
table.insert(choices, tostring(index) .. ': ' .. choice)
|
||||
end
|
||||
local index = vim.fn.inputlist(choices)
|
||||
build.dir = dirs[index]
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function build.run(args)
|
||||
-- Check if build dir set, if not prompt user to select one
|
||||
if not build.dir then
|
||||
build.select_dir(function() build.run(args) end)
|
||||
return
|
||||
end
|
||||
local command = nil
|
||||
if vim.fn.filereadable(build.dir .. '/build.ninja') then
|
||||
command = 'ninja'
|
||||
elseif vim.fn.filereadable(build.dir .. '/Makefile') then
|
||||
command = 'make'
|
||||
else
|
||||
echo('could not find build.ninja or Makefile in: ' .. build.dir)
|
||||
return
|
||||
end
|
||||
command = command .. ' -C ' .. build.dir .. ' ' .. vim.fn.join(args, ' ')
|
||||
-- TODO: Figure out how to make the terminal window close on success
|
||||
-- TODO: Running the terminal in a togglable floating window might be nice
|
||||
vim.fn.execute('split | terminal ' .. command)
|
||||
end
|
||||
|
||||
function build.list_dirs()
|
||||
local dirs = vim.fn.globpath('.', 'build*')
|
||||
dirs = vim.fn.substitute(dirs, '\\.\\/', '', 'g')
|
||||
return vim.fn.split(dirs)
|
||||
end
|
||||
|
||||
function build.list_targets()
|
||||
local targets = {}
|
||||
if not build.dir then
|
||||
return targets
|
||||
end
|
||||
if vim.fn.filereadable(build.dir .. '/build.ninja') then
|
||||
-- Query ninja for the list of targets
|
||||
targets = vim.fn.systemlist('ninja -C ' .. build.dir .. ' -t targets')
|
||||
for index, target in ipairs(targets) do
|
||||
targets[index] = string.sub(target, 1, string.find(target, ':') - 1)
|
||||
end
|
||||
end
|
||||
-- TODO: Support make, it's much less straight forwards than ninja.
|
||||
return targets
|
||||
end
|
||||
|
||||
-- Create :BuildDir command
|
||||
vim.api.nvim_create_user_command('BuildDir', function(opts)
|
||||
build.set_dir(opts.fargs[1])
|
||||
end, {
|
||||
bang = true, nargs = '?', complete = build.list_dirs,
|
||||
})
|
||||
|
||||
-- Create :Build command
|
||||
vim.api.nvim_create_user_command('Build', function(opts)
|
||||
build.run(opts.fargs)
|
||||
end, {
|
||||
bang = true, nargs = '*', complete = build.list_targets,
|
||||
})
|
||||
|
||||
return build
|
||||
Reference in New Issue
Block a user