From 23425f9eeba9c02b9a2d98d53f1354bc9402200e Mon Sep 17 00:00:00 2001 From: Daniil Rozanov Date: Sat, 11 May 2024 02:33:56 +0300 Subject: format: replace tabs with spaces --- README.md | 1 + lua/cmake/actions.lua | 315 ++++++------- lua/cmake/autocmds.lua | 72 +-- lua/cmake/capabilities.lua | 70 +-- lua/cmake/commandline.lua | 209 ++++----- lua/cmake/commands.lua | 142 +++--- lua/cmake/config.lua | 106 ++--- lua/cmake/constants.lua | 4 +- lua/cmake/fileapi.lua | 148 +++--- lua/cmake/init.lua | 39 +- lua/cmake/lazy.lua | 16 +- lua/cmake/lyaml.lua | 980 ++++++++++++++++++++-------------------- lua/cmake/telescope/pickers.lua | 164 +++---- lua/cmake/terminal.lua | 169 ++++--- lua/cmake/utils.lua | 156 +++---- lua/cmake/variants.lua | 252 +++++------ 16 files changed, 1421 insertions(+), 1422 deletions(-) diff --git a/README.md b/README.md index a660a32..7ab7183 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,4 @@ Since the plugin is asynchronous, you don't have to lazily load it. Loading time and go to it's definitions, depentent target and other possible entities in any meaningful relations - [ ] quickfix +- [ ] Ability to keep one runner terminal per project or target diff --git a/lua/cmake/actions.lua b/lua/cmake/actions.lua index 230e1e3..b910a2c 100644 --- a/lua/cmake/actions.lua +++ b/lua/cmake/actions.lua @@ -10,42 +10,43 @@ local uv = vim.uv local M = {} local default_generate_exe_opts = { - notify = { - ok_message = "CMake generate finished", - err_message = function(code) - return "CMake generate failed with code " .. tostring(code) - end, - }, + notify = { + ok_message = "CMake generate finished", + err_message = function(code) + return "CMake generate failed with code " .. tostring(code) + end, + }, } local default_build_exe_opts = { - notify = { - ok_message = "CMake build finished", - err_message = function(code) - return "CMake build failed with code " .. tostring(code) - end, - }, + notify = { + ok_message = "CMake build finished", + err_message = function(code) + return "CMake build failed with code " .. tostring(code) + end, + }, } local _explain = function(command) - vim.notify( - table.concat({ - table.concat( - vim.iter(command.env or {}) - :map(function(k, v) - if v:find(" ") then - return k .. '="' .. v .. '"' - end - return k .. "=" .. v - end) - :totable(), - " " - ), - command.cmd, - command.args, - }, " "), - vim.log.levels.INFO - ) + vim.notify( + table.concat({ + table.concat( + vim + .iter(command.env or {}) + :map(function(k, v) + if v:find(" ") then + return k .. '="' .. v .. '"' + end + return k .. "=" .. v + end) + :totable(), + " " + ), + command.cmd, + command.args, + }, " "), + vim.log.levels.INFO + ) end --- Extends generate command by given options @@ -53,9 +54,9 @@ end ---@param opts GenerateOpts ---@return table local _extend_generate_command = function(command, opts) - opts = opts or {} - local new = vim.deepcopy(command) - return new + opts = opts or {} + local new = vim.deepcopy(command) + return new end --- Extends build command by given options @@ -63,41 +64,41 @@ end ---@param opts BuildOpts ---@return table local _extend_build_command = function(command, opts) - local new = vim.deepcopy(command) - if opts.j then - new.args = new.args .. " -j " .. tostring(opts.j) - end - if opts.clean then - new.args = new.args .. " --clean-first" - end - if opts.target and #opts.target ~= 0 then - new.args = new.args .. " --target " .. table.concat(opts.target, " ") - end - return new + local new = vim.deepcopy(command) + if opts.j then + new.args = new.args .. " -j " .. tostring(opts.j) + end + if opts.clean then + new.args = new.args .. " --clean-first" + end + if opts.target and #opts.target ~= 0 then + new.args = new.args .. " --target " .. table.concat(opts.target, " ") + end + return new end local _generate = function(option, opts) - opts = opts or {} - local main_path = function() - pr.create_fileapi_query({}, function() - vim.schedule(function() - t.cmake_execute(_extend_generate_command(option.generate_command, opts), default_generate_exe_opts) - end) - end) - end - if opts.fresh then - pr.clear_cache() - end - main_path() + opts = opts or {} + local main_path = function() + pr.create_fileapi_query({}, function() + vim.schedule(function() + t.cmake_execute(_extend_generate_command(option.generate_command, opts), default_generate_exe_opts) + end) + end) + end + if opts.fresh then + pr.clear_cache() + end + main_path() end local _for_current_generate_option = function(func) - local idx = pr.current_generate_option_idx() - if not idx then - vim.notify("CMake: no configuration to generate", vim.log.levels.WARN) - else - func(pr.current_generate_option()) - end + local idx = pr.current_generate_option_idx() + if not idx then + vim.notify("CMake: no configuration to generate", vim.log.levels.WARN) + else + func(pr.current_generate_option()) + end end ---@class GenerateOpts @@ -106,55 +107,55 @@ end --- Generate project with current generate option --- @param opts GenerateOpts M.generate = function(opts) - opts = opts or {} - _for_current_generate_option(function(option) - _generate(option, opts) - end) + opts = opts or {} + _for_current_generate_option(function(option) + _generate(option, opts) + end) end --- Generate project with current generate option --- @param opts GenerateOpts M.generate_explain = function(opts) - opts = opts or {} - _for_current_generate_option(function(option) - _explain(_extend_generate_command(option.generate_command, opts)) - end) + opts = opts or {} + _for_current_generate_option(function(option) + _explain(_extend_generate_command(option.generate_command, opts)) + end) end --- Generate project with current generate option --- @param opts table|nil M.generate_select = function(opts) - opts = opts or {} - local items = pr.generate_options(opts) - vim.ui.select(items, { - prompt = "Select configuration to generate:", - format_item = function(item) - return table.concat(item.name, config.variants_display.short.sep) - end, - }, function(_, idx) - if not idx then - return - end - pr.set_current_generate_option(idx) - end) + opts = opts or {} + local items = pr.generate_options(opts) + vim.ui.select(items, { + prompt = "Select configuration to generate:", + format_item = function(item) + return table.concat(item.name, config.variants_display.short.sep) + end, + }, function(_, idx) + if not idx then + return + end + pr.set_current_generate_option(idx) + end) end local _for_current_build_option = function(func) - local idx = pr.current_build_option() - if not idx then - vim.notify("CMake: no build configuration to generate", vim.log.levels.WARN) - else - func(pr.current_build_option()) - end + local idx = pr.current_build_option() + if not idx then + vim.notify("CMake: no build configuration to generate", vim.log.levels.WARN) + else + func(pr.current_build_option()) + end end local _build = function(option, opts) - opts = opts or {} - pr.create_fileapi_query({}, function() - vim.schedule(function() - t.cmake_execute(_extend_build_command(option.command, opts), default_build_exe_opts) - end) - end) + opts = opts or {} + pr.create_fileapi_query({}, function() + vim.schedule(function() + t.cmake_execute(_extend_build_command(option.command, opts), default_build_exe_opts) + end) + end) end ---@class BuildOpts @@ -165,44 +166,44 @@ end --- Build project with current build option --- @param opts BuildOpts M.build = function(opts) - opts = opts or {} - _for_current_build_option(function(option) - _build(option, opts) - end) + opts = opts or {} + _for_current_build_option(function(option) + _build(option, opts) + end) end --- Build project with current build option --- @param opts BuildOpts M.build_explain = function(opts) - opts = opts or {} - _for_current_build_option(function(option) - _explain(_extend_build_command(option.command, opts)) - end) + opts = opts or {} + _for_current_build_option(function(option) + _explain(_extend_build_command(option.command, opts)) + end) end ---Change current build option ---@param opts any|nil M.build_select = function(opts) - local items = pr.current_generate_option().build_options - vim.ui.select(items, { - prompt = "Select build option to generate:", - format_item = function(item) - return table.concat(item.name, config.variants_display.short.sep) - end, - }, function(_, idx) - if not idx then - return - end - pr.set_current_build_option(idx) - end) + local items = pr.current_generate_option().build_options + vim.ui.select(items, { + prompt = "Select build option to generate:", + format_item = function(item) + return table.concat(item.name, config.variants_display.short.sep) + end, + }, function(_, idx) + if not idx then + return + end + pr.set_current_build_option(idx) + end) end local _run_target = function(opts) - local command = { - cmd = opts.path, - cwd = pr.current_directory(), - } - t.target_execute(command) + local command = { + cmd = opts.path, + cwd = pr.current_directory(), + } + t.target_execute(command) end ---@class RunTargetOpts @@ -211,58 +212,58 @@ end --- Run target --- @param opts RunTargetOpts M.run_target = function(opts) - opts = opts or {} - local _curr_exe_cmd = pr.current_executable_target() - if not _curr_exe_cmd then - M.run_target_select(opts) - else - _run_target({ path = _curr_exe_cmd.path }) - end + opts = opts or {} + local _curr_exe_cmd = pr.current_executable_target() + if not _curr_exe_cmd then + M.run_target_select(opts) + else + _run_target({ path = _curr_exe_cmd.path }) + end end --- Select target to run M.run_target_select = function(opts) - opts = opts or {} - opts.type = "EXECUTABLE" - local items = pr.current_targets(opts) - vim.ui.select(items, { - prompt = "Select tagret to run:", - format_item = function(item) - return item.name - end, - }, function(_, idx) - if not idx then - return - end - pr.set_current_executable_target(idx) - end) + opts = opts or {} + opts.type = "EXECUTABLE" + local items = pr.current_targets(opts) + vim.ui.select(items, { + prompt = "Select tagret to run:", + format_item = function(item) + return item.name + end, + }, function(_, idx) + if not idx then + return + end + pr.set_current_executable_target(idx) + end) end ---Toggle CMake terminal window M.toggle = function() - t.cmake_toggle() + t.cmake_toggle() end ---Edit `.cmake-variants.yaml` file M.edit_variants = function() - utils.file_exists(constants.variants_yaml_filename, function(variants_exists) - if variants_exists then - vim.schedule(function() - vim.cmd(string.format("e %s", constants.variants_yaml_filename)) - end) - else - local default_yaml = require("cmake.lyaml").dump(config.variants) - utils.write_file(constants.variants_yaml_filename, default_yaml, function() - vim.schedule(function() - vim.cmd(string.format("e %s", constants.variants_yaml_filename)) - end) - end) - end - end) + utils.file_exists(constants.variants_yaml_filename, function(variants_exists) + if variants_exists then + vim.schedule(function() + vim.cmd(string.format("e %s", constants.variants_yaml_filename)) + end) + else + local default_yaml = require("cmake.lyaml").dump(config.variants) + utils.write_file(constants.variants_yaml_filename, default_yaml, function() + vim.schedule(function() + vim.cmd(string.format("e %s", constants.variants_yaml_filename)) + end) + end) + end + end) end M.reset_project = function(opts) - require("cmake.project").setup(opts) + require("cmake.project").setup(opts) end return M diff --git a/lua/cmake/autocmds.lua b/lua/cmake/autocmds.lua index 5bbfbe8..a584b52 100644 --- a/lua/cmake/autocmds.lua +++ b/lua/cmake/autocmds.lua @@ -7,45 +7,45 @@ local autocmds = {} local cmake_nvim_augroup = vim.api.nvim_create_augroup("CMake", {}) function autocmds.set_on_variants() - vim.api.nvim_create_autocmd({ "BufWritePost" }, { - group = cmake_nvim_augroup, - pattern = constants.variants_yaml_filename, - callback = function(args) - actions.reset_project() - end, - desc = "Setup project after saving variants", - }) + vim.api.nvim_create_autocmd({ "BufWritePost" }, { + group = cmake_nvim_augroup, + pattern = constants.variants_yaml_filename, + callback = function(args) + actions.reset_project() + end, + desc = "Setup project after saving variants", + }) end function autocmds.setup() - if config.generate_after_save then - vim.api.nvim_create_autocmd({ "BufWritePost" }, { - group = cmake_nvim_augroup, - pattern = constants.cmakelists, - callback = function(args) - actions.generate() - end, - desc = "Generate project after saving CMakeLists.txt", - }) - end - --NOTE: this autocmd was written only to handle very rare case when inside directory - --without CMakeLists.txt neovim starts like `nvim CMakeLists.txt`. In this case initial - --setup will not make the affect and to correctry process the file save, we need to create - --this autocommand so it reinitializes the project if it has not been done before. IMHO this - --is not the best way to do this. Also, if newly buffer associated with CMakeLists.txt will not - --be saved and just closed, but user will continue to use nvim, CMake commands still will be - --able while it sholdn't. Two options is give up or handle all this corner cases - -- - -- if config.generate_after_save then - -- vim.api.nvim_create_autocmd({ "BufEnter" }, { - -- group = cmake_nvim_augroup, - -- pattern = constants.cmakelists, - -- callback = function(args) - -- actions.reset_project({ first_time_only = true }) - -- end, - -- desc = "Set up project on open CMakeLists.txt if not set before", - -- }) - -- end + if config.generate_after_save then + vim.api.nvim_create_autocmd({ "BufWritePost" }, { + group = cmake_nvim_augroup, + pattern = constants.cmakelists, + callback = function(args) + actions.generate() + end, + desc = "Generate project after saving CMakeLists.txt", + }) + end + --NOTE: this autocmd was written only to handle very rare case when inside directory + --without CMakeLists.txt neovim starts like `nvim CMakeLists.txt`. In this case initial + --setup will not make the affect and to correctry process the file save, we need to create + --this autocommand so it reinitializes the project if it has not been done before. IMHO this + --is not the best way to do this. Also, if newly buffer associated with CMakeLists.txt will not + --be saved and just closed, but user will continue to use nvim, CMake commands still will be + --able while it sholdn't. Two options is give up or handle all this corner cases + -- + -- if config.generate_after_save then + -- vim.api.nvim_create_autocmd({ "BufEnter" }, { + -- group = cmake_nvim_augroup, + -- pattern = constants.cmakelists, + -- callback = function(args) + -- actions.reset_project({ first_time_only = true }) + -- end, + -- desc = "Set up project on open CMakeLists.txt if not set before", + -- }) + -- end end return autocmds diff --git a/lua/cmake/capabilities.lua b/lua/cmake/capabilities.lua index 0b76fc0..5cc3f21 100644 --- a/lua/cmake/capabilities.lua +++ b/lua/cmake/capabilities.lua @@ -1,56 +1,56 @@ local config = require("cmake.config") local multiconfig_generators = { - "Ninja Multi-Config", - "Xcode", - "Visual Studio 12 2013", - "Visual Studio 14 2015", - "Visual Studio 15 2017", - "Visual Studio 16 2019", - "Visual Studio 17 2022", - "Green Hills MULTI", + "Ninja Multi-Config", + "Xcode", + "Visual Studio 12 2013", + "Visual Studio 14 2015", + "Visual Studio 15 2017", + "Visual Studio 16 2019", + "Visual Studio 17 2022", + "Green Hills MULTI", } local Capabilities = { - json = nil, + json = nil, } function Capabilities.generators() - local ret = {} - if not Capabilities then - return ret - end - for k, v in pairs(Capabilities.json.generators) do - table.insert(ret, v.name) - end - return vim.fn.reverse(ret) + local ret = {} + if not Capabilities then + return ret + end + for k, v in pairs(Capabilities.json.generators) do + table.insert(ret, v.name) + end + return vim.fn.reverse(ret) end function Capabilities.is_multiconfig_generator(generator) - -- if generator is nil, assume is is not multiconifg - if not generator then - return - end - return vim.tbl_contains(multiconfig_generators, generator) + -- if generator is nil, assume is is not multiconifg + if not generator then + return + end + return vim.tbl_contains(multiconfig_generators, generator) end function Capabilities.has_fileapi() - return vim.tbl_get(Capabilities.json, "fileApi") ~= nil + return vim.tbl_get(Capabilities.json, "fileApi") ~= nil end Capabilities.setup = function(callback) - vim.schedule(function() - vim.system({ config.cmake.cmake_path, "-E", "capabilities" }, { text = true }, function(obj) - if obj.code == 0 then - Capabilities.json = vim.json.decode(obj.stdout) - if type(callback) == "function" then - callback() - end - else - vim.notify("error " .. tostring(obj.code) .. ". 'cmake -E capabilities'", vim.log.levels.ERROR) - end - end) - end) + vim.schedule(function() + vim.system({ config.cmake.cmake_path, "-E", "capabilities" }, { text = true }, function(obj) + if obj.code == 0 then + Capabilities.json = vim.json.decode(obj.stdout) + if type(callback) == "function" then + callback() + end + else + vim.notify("error " .. tostring(obj.code) .. ". 'cmake -E capabilities'", vim.log.levels.ERROR) + end + end) + end) end return Capabilities diff --git a/lua/cmake/commandline.lua b/lua/cmake/commandline.lua index c3d0ef1..06577d5 100644 --- a/lua/cmake/commandline.lua +++ b/lua/cmake/commandline.lua @@ -9,112 +9,115 @@ local M = {} ---@param typed_path string ---@return string|nil, string|nil local get_path_parts = function(typed_path) - if vim.fn.isdirectory(typed_path ~= "" and typed_path or ".") == 1 then - -- The string is a valid path, we just need to drop trailing slashes to - -- ease joining the base path with the suggestions - return typed_path:gsub("/$", ""), nil - elseif typed_path:find("/", 2) ~= nil then - -- Maybe the typed path is looking for a nested directory - -- we need to make sure it has at least one slash in it, and that is not - -- from a root path - local base_path = vim.fn.fnamemodify(typed_path, ":h") - local search_term = vim.fn.fnamemodify(typed_path, ":t") - if vim.fn.isdirectory(base_path) then - return base_path, search_term - end - end - - return nil, nil + if vim.fn.isdirectory(typed_path ~= "" and typed_path or ".") == 1 then + -- The string is a valid path, we just need to drop trailing slashes to + -- ease joining the base path with the suggestions + return typed_path:gsub("/$", ""), nil + elseif typed_path:find("/", 2) ~= nil then + -- Maybe the typed path is looking for a nested directory + -- we need to make sure it has at least one slash in it, and that is not + -- from a root path + local base_path = vim.fn.fnamemodify(typed_path, ":h") + local search_term = vim.fn.fnamemodify(typed_path, ":t") + if vim.fn.isdirectory(base_path) then + return base_path, search_term + end + end + + return nil, nil end local complete_path = function(typed_path) - -- Read the typed path as the base for the directory search - local base_path, search_term = get_path_parts(typed_path or "") - local safe_path = base_path ~= "" and base_path or "." - - local paths = vim.fn.readdir(safe_path, function(entry) - return vim.fn.isdirectory(safe_path .. "/" .. entry) - end) - - if not u.str_is_empty(search_term) then - paths = vim.tbl_filter(function(path) - return path:match("^" .. search_term .. "*") ~= nil - end, paths) - end - - return vim.tbl_map(function(path) - return u.concat_without_empty({ base_path, path }, "/") - end, paths) + -- Read the typed path as the base for the directory search + local base_path, search_term = get_path_parts(typed_path or "") + local safe_path = base_path ~= "" and base_path or "." + + local paths = vim.fn.readdir(safe_path, function(entry) + return vim.fn.isdirectory(safe_path .. "/" .. entry) + end) + + if not u.str_is_empty(search_term) then + paths = vim.tbl_filter(function(path) + return path:match("^" .. search_term .. "*") ~= nil + end, paths) + end + + return vim.tbl_map(function(path) + return u.concat_without_empty({ base_path, path }, "/") + end, paths) end local generate_options = { - fresh = true, + fresh = true, } local complete_value = function(values, values_opts, match) - return function(typed_value) - typed_value = typed_value or "" - return vim.iter(values(values_opts)) - :filter(function(value) - return not typed_value or #typed_value == 0 or value[match]:match("^" .. typed_value .. "*") - end) - :map(function(value) - return value[match] - end) - :totable() - end + return function(typed_value) + typed_value = typed_value or "" + return vim + .iter(values(values_opts)) + :filter(function(value) + return not typed_value or #typed_value == 0 or value[match]:match("^" .. typed_value .. "*") + end) + :map(function(value) + return value[match] + end) + :totable() + end end local build_options = { - clean = true, - j = function() - return {} - end, - target = complete_value(project.current_targets, {}, "name"), + clean = true, + j = function() + return {} + end, + target = complete_value(project.current_targets, {}, "name"), } local install_options = { - explain = true, - -- component = complete_value(project.current_components, {}, "name"), - prefix = complete_path, + explain = true, + -- component = complete_value(project.current_components, {}, "name"), + prefix = complete_path, } ---@param options table a dictionary of key to function ---@return fun(lead: string, command: string, _: number):table local function complete(options) - ---@param lead string the leading portion of the argument currently being completed on - ---@param command string the entire command line - ---@param _ number the cursor position in it (byte index) - ---@return table - return function(lead, command, _) - local parts = vim.split(lead, "=") - local key = parts[1] - local value = parts[2] - if options[key] then - if type(options[key]) == "function" then - return vim.iter(options[key](value)) - :map(function(opt) - return key .. "=" .. opt - end) - :totable() - else - return {} - end - else - return vim.iter(options) - :filter(function(option, _) - return option:match(" " .. option .. "=") == nil - end) - :map(function(option, option_value) - if type(option_value) == "boolean" and option_value then - return option - else - return option .. "=" - end - end) - :totable() - end - end + ---@param lead string the leading portion of the argument currently being completed on + ---@param command string the entire command line + ---@param _ number the cursor position in it (byte index) + ---@return table + return function(lead, command, _) + local parts = vim.split(lead, "=") + local key = parts[1] + local value = parts[2] + if options[key] then + if type(options[key]) == "function" then + return vim + .iter(options[key](value)) + :map(function(opt) + return key .. "=" .. opt + end) + :totable() + else + return {} + end + else + return vim + .iter(options) + :filter(function(option, _) + return option:match(" " .. option .. "=") == nil + end) + :map(function(option, option_value) + if type(option_value) == "boolean" and option_value then + return option + else + return option .. "=" + end + end) + :totable() + end + end end ---Take a users command arguments in format 'key1=value key2' @@ -123,23 +126,23 @@ end ---@param args string ---@return any function M.parse(args) - local result = {} - if args then - for _, part in ipairs(vim.split(args, " ")) do - local arg = vim.split(part, "=") - local key, value = arg[1], arg[2] - if not value then - result[key] = true - else - if key == "target" then - result[key] = vim.split(value, ",") - else - result[key] = value - end - end - end - end - return result + local result = {} + if args then + for _, part in ipairs(vim.split(args, " ")) do + local arg = vim.split(part, "=") + local key, value = arg[1], arg[2] + if not value then + result[key] = true + else + if key == "target" then + result[key] = vim.split(value, ",") + else + result[key] = value + end + end + end + end + return result end M.cmake_generate_complete = complete(generate_options) diff --git a/lua/cmake/commands.lua b/lua/cmake/commands.lua index 03b20a3..8275fc8 100644 --- a/lua/cmake/commands.lua +++ b/lua/cmake/commands.lua @@ -9,80 +9,80 @@ local cmd = vim.api.nvim_create_user_command local prefix = "CMake" local commands = { - ["Generate"] = { - command = actions.generate, - parse = true, - default_opts = { fresh = false }, - cmd_opts = { - desc = "Generate with last configuration", - nargs = "*", - complete = commandline.cmake_generate_complete, - }, - }, - ["GenerateExplain"] = { - command = actions.generate_explain, - parse = true, - default_opts = { fresh = false }, - cmd_opts = { - desc = "Explain current generate command", - nargs = "*", - complete = commandline.cmake_generate_complete, - }, - }, - ["GenerateSelect"] = { - command = actions.generate_select, - cmd_opts = { desc = "Select generate configuration" }, - }, - ["Build"] = { - command = actions.build, - parse = true, - cmd_opts = { - desc = "Build with last configuration", - nargs = "*", - complete = commandline.cmake_build_complete, - }, - }, - ["BuildExplain"] = { - command = actions.build_explain, - parse = true, - cmd_opts = { - desc = "Explain current build command", - nargs = "*", - complete = commandline.cmake_build_complete, - }, - }, - ["BuildSelect"] = { - command = actions.build_select, - cmd_opts = { desc = "Select build configuration" }, - }, - ["Run"] = { - command = actions.run_target, - cmd_opts = { desc = "Run current executable target", nargs = "*" }, - }, - ["RunSelect"] = { - command = actions.run_target_select, - cmd_opts = { desc = "Select executable target" }, - }, - ["Toggle"] = { - command = actions.toggle, - cmd_opts = { desc = "Toggle cmake terminal" }, - }, - ["EditVariants"] = { - command = actions.edit_variants, - cmd_opts = { desc = "Edit variants" }, - }, + ["Generate"] = { + command = actions.generate, + parse = true, + default_opts = { fresh = false }, + cmd_opts = { + desc = "Generate with last configuration", + nargs = "*", + complete = commandline.cmake_generate_complete, + }, + }, + ["GenerateExplain"] = { + command = actions.generate_explain, + parse = true, + default_opts = { fresh = false }, + cmd_opts = { + desc = "Explain current generate command", + nargs = "*", + complete = commandline.cmake_generate_complete, + }, + }, + ["GenerateSelect"] = { + command = actions.generate_select, + cmd_opts = { desc = "Select generate configuration" }, + }, + ["Build"] = { + command = actions.build, + parse = true, + cmd_opts = { + desc = "Build with last configuration", + nargs = "*", + complete = commandline.cmake_build_complete, + }, + }, + ["BuildExplain"] = { + command = actions.build_explain, + parse = true, + cmd_opts = { + desc = "Explain current build command", + nargs = "*", + complete = commandline.cmake_build_complete, + }, + }, + ["BuildSelect"] = { + command = actions.build_select, + cmd_opts = { desc = "Select build configuration" }, + }, + ["Run"] = { + command = actions.run_target, + cmd_opts = { desc = "Run current executable target", nargs = "*" }, + }, + ["RunSelect"] = { + command = actions.run_target_select, + cmd_opts = { desc = "Select executable target" }, + }, + ["Toggle"] = { + command = actions.toggle, + cmd_opts = { desc = "Toggle cmake terminal" }, + }, + ["EditVariants"] = { + command = actions.edit_variants, + cmd_opts = { desc = "Edit variants" }, + }, } M.register_commands = function() - for k, v in pairs(commands) do - cmd(prefix .. k, function(opts) - local action_opts = v.default_opts or {} - if v.parse then - action_opts = vim.tbl_deep_extend("keep", commandline.parse(opts.args) or {}, action_opts) - end - v.command(action_opts) - end, v.cmd_opts) - end + for k, v in pairs(commands) do + cmd(prefix .. k, function(opts) + local action_opts = v.default_opts or {} + if v.parse then + action_opts = vim.tbl_deep_extend("keep", commandline.parse(opts.args) or {}, action_opts) + end + v.command(action_opts) + end, v.cmd_opts) + end end return M diff --git a/lua/cmake/config.lua b/lua/cmake/config.lua index 6ac5856..b4b2bf7 100644 --- a/lua/cmake/config.lua +++ b/lua/cmake/config.lua @@ -51,55 +51,55 @@ ---@type CMakeConfig local default_config = { - cmake = { - cmake_path = "cmake", - ctest_path = "ctest", - cpack_path = "cpack", - environment = {}, - configure_environment = {}, - build_directory = "${workspaceFolder}/build-${buildType}", - build_environment = {}, - build_args = {}, - build_tool_args = {}, - generator = nil, - parallel_jobs = nil, - }, - variants = { - buildType = { - default = "debug", - description = "Build type", - choices = { - debug = { short = "Debug", buildType = "Debug" }, - release = { short = "Release", buildType = "Release" }, - relWithDebInfo = { short = "RelWithDebInfo", buildType = "RelWithDebInfo" }, - minSizeRel = { short = "MinSizeRel", buildType = "MinSizeRel" }, - }, - }, - }, - save_before_build = true, - generate_after_save = true, - cmake_terminal = { - split = "below", - size = 15, - close_on_exit = "success", - open_on_start = true, - clear_env = false, - enter = false, - }, - target_terminal = { - split = "below", - size = 15, - enter = true, - immediately = true, - }, - notification = { - after = "success", - }, - variants_display = { - short = { sep = " × ", show = true }, - long = { sep = " ❄ ", show = false }, - }, - keybinds = {}, + cmake = { + cmake_path = "cmake", + ctest_path = "ctest", + cpack_path = "cpack", + environment = {}, + configure_environment = {}, + build_directory = "${workspaceFolder}/build-${buildType}", + build_environment = {}, + build_args = {}, + build_tool_args = {}, + generator = nil, + parallel_jobs = nil, + }, + variants = { + buildType = { + default = "debug", + description = "Build type", + choices = { + debug = { short = "Debug", buildType = "Debug" }, + release = { short = "Release", buildType = "Release" }, + relWithDebInfo = { short = "RelWithDebInfo", buildType = "RelWithDebInfo" }, + minSizeRel = { short = "MinSizeRel", buildType = "MinSizeRel" }, + }, + }, + }, + save_before_build = true, + generate_after_save = true, + cmake_terminal = { + split = "below", + size = 15, + close_on_exit = "success", + open_on_start = true, + clear_env = false, + enter = false, + }, + target_terminal = { + split = "below", + size = 15, + enter = true, + immediately = true, + }, + notification = { + after = "success", + }, + variants_display = { + short = { sep = " × ", show = true }, + long = { sep = " ❄ ", show = false }, + }, + keybinds = {}, } local M = vim.deepcopy(default_config) @@ -107,11 +107,11 @@ local M = vim.deepcopy(default_config) ---Setup configs ---@param opts CMakeConfig M.setup = function(opts) - local newconf = vim.tbl_deep_extend("force", default_config, opts or {}) + local newconf = vim.tbl_deep_extend("force", default_config, opts or {}) - for k, v in pairs(newconf) do - M[k] = v - end + for k, v in pairs(newconf) do + M[k] = v + end end return M diff --git a/lua/cmake/constants.lua b/lua/cmake/constants.lua index 95f15b3..5fb836e 100644 --- a/lua/cmake/constants.lua +++ b/lua/cmake/constants.lua @@ -1,4 +1,4 @@ return { - variants_yaml_filename = "cmake-variants.yaml", - cmakelists = "CMakeLists.txt", + variants_yaml_filename = "cmake-variants.yaml", + cmakelists = "CMakeLists.txt", } diff --git a/lua/cmake/fileapi.lua b/lua/cmake/fileapi.lua index 612fd59..70e19c8 100644 --- a/lua/cmake/fileapi.lua +++ b/lua/cmake/fileapi.lua @@ -18,89 +18,89 @@ local FileApi = {} ---@field path string|nil Path to executable associated with target function FileApi.create(path, callback) - local query = vim.fs.joinpath(path, unpack(query_path_suffix)) - utils.file_exists(query, function(exists) - if not exists then - if capabilities.json.fileApi then - vim.schedule(function() - vim.fn.mkdir(vim.fs.dirname(query), "p") - utils.write_file(query, vim.json.encode(capabilities.json.fileApi), callback) - end) - else - vim.notify("Bad fileApi ", vim.log.levels.ERROR) - end - else - callback() - end - end) + local query = vim.fs.joinpath(path, unpack(query_path_suffix)) + utils.file_exists(query, function(exists) + if not exists then + if capabilities.json.fileApi then + vim.schedule(function() + vim.fn.mkdir(vim.fs.dirname(query), "p") + utils.write_file(query, vim.json.encode(capabilities.json.fileApi), callback) + end) + else + vim.notify("Bad fileApi ", vim.log.levels.ERROR) + end + else + callback() + end + end) end function FileApi.read_reply(path, callback) - local reply_dir = vim.fs.joinpath(path, unpack(reply_dir_suffix)) - utils.file_exists(reply_dir, function(exists) - if not exists then - return - end - local ret = { targets = {} } - --TODO: replace with uv scandir - scan.scan_dir_async(reply_dir, { - search_pattern = "index*", - on_exit = function(results) - if #results == 0 then - return - end - utils.read_file(results[1], function(index_data) - local index = vim.json.decode(index_data) - for _, object in ipairs(index.objects) do - if object.kind == "codemodel" then - utils.read_file(vim.fs.joinpath(reply_dir, object.jsonFile), function(codemodel_data) - local codemodel = vim.json.decode(codemodel_data) - for _, target in ipairs(codemodel.configurations[1].targets) do - local work = vim.uv.new_work(utils.read_file_sync, function(target_data) - local target_json = vim.json.decode(target_data) - ---@type CMakeTarget - local _target = { - id = target_json.id, - name = target_json.name, - type = target_json.type, - path = nil, - } - if target_json.artifacts then - --NOTE: add_library( OBJECT ...) could contain more than ohe object in artifacts - -- so maybe in future it will be useful to handle not only first one. Current behaviour - -- aims to get path for only EXECUTABLE targets - _target.path = target_json.artifacts[1].path - end - callback(_target) - end) - vim.uv.queue_work(work, vim.fs.joinpath(reply_dir, target.jsonFile)) - end - end) - end - end - end) - end, - }) - return ret - end) + local reply_dir = vim.fs.joinpath(path, unpack(reply_dir_suffix)) + utils.file_exists(reply_dir, function(exists) + if not exists then + return + end + local ret = { targets = {} } + --TODO: replace with uv scandir + scan.scan_dir_async(reply_dir, { + search_pattern = "index*", + on_exit = function(results) + if #results == 0 then + return + end + utils.read_file(results[1], function(index_data) + local index = vim.json.decode(index_data) + for _, object in ipairs(index.objects) do + if object.kind == "codemodel" then + utils.read_file(vim.fs.joinpath(reply_dir, object.jsonFile), function(codemodel_data) + local codemodel = vim.json.decode(codemodel_data) + for _, target in ipairs(codemodel.configurations[1].targets) do + local work = vim.uv.new_work(utils.read_file_sync, function(target_data) + local target_json = vim.json.decode(target_data) + ---@type CMakeTarget + local _target = { + id = target_json.id, + name = target_json.name, + type = target_json.type, + path = nil, + } + if target_json.artifacts then + --NOTE: add_library( OBJECT ...) could contain more than ohe object in artifacts + -- so maybe in future it will be useful to handle not only first one. Current behaviour + -- aims to get path for only EXECUTABLE targets + _target.path = target_json.artifacts[1].path + end + callback(_target) + end) + vim.uv.queue_work(work, vim.fs.joinpath(reply_dir, target.jsonFile)) + end + end) + end + end + end) + end, + }) + return ret + end) end function FileApi.query_exists(path, callback) - utils.file_exists(vim.fs.joinpath(path, unpack(query_path_suffix)), function(query_exists) - callback(query_exists) - end) + utils.file_exists(vim.fs.joinpath(path, unpack(query_path_suffix)), function(query_exists) + callback(query_exists) + end) end function FileApi.exists(path, callback) - FileApi.query_exists(path, function(query_exists) - if not query_exists then - callback(false) - else - utils.file_exists(vim.fs.joinpath(path, unpack(reply_dir_suffix)), function(reply_exists) - callback(reply_exists) - end) - end - end) + FileApi.query_exists(path, function(query_exists) + if not query_exists then + callback(false) + else + utils.file_exists(vim.fs.joinpath(path, unpack(reply_dir_suffix)), function(reply_exists) + callback(reply_exists) + end) + end + end) end return FileApi diff --git a/lua/cmake/init.lua b/lua/cmake/init.lua index 6d7843c..5cff2dc 100644 --- a/lua/cmake/init.lua +++ b/lua/cmake/init.lua @@ -9,27 +9,24 @@ local uv = vim.uv local M = {} function M.setup(opts) - opts = opts or {} - config.setup(opts) - if vim.fn.executable(config.cmake.cmake_path) then - autocmds.setup() - utils.file_exists(vim.fs.joinpath(uv.cwd(), constants.cmakelists), function(cmake_lists_exists) - if cmake_lists_exists then - --TODO: init autocommands needs to be related with project setup - vim.schedule(function() - autocmds.set_on_variants() - commands.register_commands() - end) - require("cmake.project").setup() - else - end - end) - else - vim.notify( - "CMake: " .. config.cmake.cmake_path .. " is not executable. Plugin is unavailable", - vim.log.levels.WARN - ) - end + opts = opts or {} + config.setup(opts) + if vim.fn.executable(config.cmake.cmake_path) then + autocmds.setup() + utils.file_exists(vim.fs.joinpath(uv.cwd(), constants.cmakelists), function(cmake_lists_exists) + if cmake_lists_exists then + --TODO: init autocommands needs to be related with project setup + vim.schedule(function() + autocmds.set_on_variants() + commands.register_commands() + end) + require("cmake.project").setup() + else + end + end) + else + vim.notify("CMake: " .. config.cmake.cmake_path .. " is not executable. Plugin is unavailable", vim.log.levels.WARN) + end end return M diff --git a/lua/cmake/lazy.lua b/lua/cmake/lazy.lua index 7669dcd..c9b4a2f 100644 --- a/lua/cmake/lazy.lua +++ b/lua/cmake/lazy.lua @@ -7,15 +7,15 @@ local lazy = {} ---@param require_path string ---@return table lazy.require = function(require_path) - return setmetatable({}, { - __index = function(_, key) - return require(require_path)[key] - end, + return setmetatable({}, { + __index = function(_, key) + return require(require_path)[key] + end, - __newindex = function(_, key, value) - require(require_path)[key] = value - end, - }) + __newindex = function(_, key, value) + require(require_path)[key] = value + end, + }) end return lazy diff --git a/lua/cmake/lyaml.lua b/lua/cmake/lyaml.lua index 3a17cc1..cf558c5 100644 --- a/lua/cmake/lyaml.lua +++ b/lua/cmake/lyaml.lua @@ -18,478 +18,478 @@ local table_print_value table_print_value = function(value, indent, done) - indent = indent or 0 - done = done or {} - if type(value) == "table" then - -- done[value] = true - - local rep = "\n" - for key, val in pairs(value) do - local keyRep - if type(key) == "number" then - keyRep = "-" - else - keyRep = string.format("%s:", tostring(key)) - end - local child_indent = indent + 2 - rep = rep - .. string - .format("%s%s %s\n", string.rep(" ", indent), keyRep, table_print_value(val, child_indent, done)) - :gsub("\n\n", "\n") - end - - -- rep = rep .. string.rep(" ", indent) -- indent it - - -- done[value] = false - return rep - elseif type(value) == "string" then - return string.format("%q", value) - else - return tostring(value) - end + indent = indent or 0 + done = done or {} + if type(value) == "table" then + -- done[value] = true + + local rep = "\n" + for key, val in pairs(value) do + local keyRep + if type(key) == "number" then + keyRep = "-" + else + keyRep = string.format("%s:", tostring(key)) + end + local child_indent = indent + 2 + rep = rep + .. string + .format("%s%s %s\n", string.rep(" ", indent), keyRep, table_print_value(val, child_indent, done)) + :gsub("\n\n", "\n") + end + + -- rep = rep .. string.rep(" ", indent) -- indent it + + -- done[value] = false + return rep + elseif type(value) == "string" then + return string.format("%q", value) + else + return tostring(value) + end end local table_print = function(tt) - return vim.trim(table_print_value(tt)) + return vim.trim(table_print_value(tt)) end local table_clone = function(t) - local clone = {} - for k, v in pairs(t) do - clone[k] = v - end - return clone + local clone = {} + for k, v in pairs(t) do + clone[k] = v + end + return clone end local string_trim = function(s, what) - what = what or " " - return s:gsub("^[" .. what .. "]*(.-)[" .. what .. "]*$", "%1") + what = what or " " + return s:gsub("^[" .. what .. "]*(.-)[" .. what .. "]*$", "%1") end local push = function(stack, item) - stack[#stack + 1] = item + stack[#stack + 1] = item end local pop = function(stack) - local item = stack[#stack] - stack[#stack] = nil - return item + local item = stack[#stack] + stack[#stack] = nil + return item end local context = function(str) - if type(str) ~= "string" then - return "" - end + if type(str) ~= "string" then + return "" + end - str = str:sub(0, 25):gsub("\n", "\\n"):gsub('"', '\\"') - return ', near "' .. str .. '"' + str = str:sub(0, 25):gsub("\n", "\\n"):gsub('"', '\\"') + return ', near "' .. str .. '"' end local Parser = {} function Parser.new(self, tokens) - self.tokens = tokens - self.parse_stack = {} - self.refs = {} - self.current = 0 - return self + self.tokens = tokens + self.parse_stack = {} + self.refs = {} + self.current = 0 + return self end local exports = { version = "1.2" } local word = function(w) - return "^(" .. w .. ")([%s$%c])" + return "^(" .. w .. ")([%s$%c])" end local tokens = { - { "comment", "^#[^\n]*" }, - { "indent", "^\n( *)" }, - { "space", "^ +" }, - { - "true", - word("enabled"), - const = true, - value = true, - }, - { - "true", - word("true"), - const = true, - value = true, - }, - { - "true", - word("yes"), - const = true, - value = true, - }, - { - "true", - word("on"), - const = true, - value = true, - }, - { - "false", - word("disabled"), - const = true, - value = false, - }, - { - "false", - word("false"), - const = true, - value = false, - }, - { - "false", - word("no"), - const = true, - value = false, - }, - { - "false", - word("off"), - const = true, - value = false, - }, - { - "null", - word("null"), - const = true, - value = nil, - }, - { - "null", - word("Null"), - const = true, - value = nil, - }, - { - "null", - word("NULL"), - const = true, - value = nil, - }, - { - "null", - word("~"), - const = true, - value = nil, - }, - { "id", '^"([^"]-)" *(:[%s%c])' }, - { "id", "^'([^']-)' *(:[%s%c])" }, - { "string", '^"([^"]-)"', force_text = true }, - { "string", "^'([^']-)'", force_text = true }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?):(%d%d)" }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?)" }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)" }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d)" }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?)" }, - { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)" }, - { "doc", "^%-%-%-[^%c]*" }, - { ",", "^," }, - { "string", "^%b{} *[^,%c]+", noinline = true }, - { "{", "^{" }, - { "}", "^}" }, - { "string", "^%b[] *[^,%c]+", noinline = true }, - { "[", "^%[" }, - { "]", "^%]" }, - { "-", "^%-", noinline = true }, - { ":", "^:" }, - { "pipe", "^(|)(%d*[+%-]?)", sep = "\n" }, - { "pipe", "^(>)(%d*[+%-]?)", sep = " " }, - { "id", "^([%w][%w %-_]*)(:[%s%c])" }, - { "string", "^[^%c]+", noinline = true }, - { "string", "^[^,%]}%c ]+" }, + { "comment", "^#[^\n]*" }, + { "indent", "^\n( *)" }, + { "space", "^ +" }, + { + "true", + word("enabled"), + const = true, + value = true, + }, + { + "true", + word("true"), + const = true, + value = true, + }, + { + "true", + word("yes"), + const = true, + value = true, + }, + { + "true", + word("on"), + const = true, + value = true, + }, + { + "false", + word("disabled"), + const = true, + value = false, + }, + { + "false", + word("false"), + const = true, + value = false, + }, + { + "false", + word("no"), + const = true, + value = false, + }, + { + "false", + word("off"), + const = true, + value = false, + }, + { + "null", + word("null"), + const = true, + value = nil, + }, + { + "null", + word("Null"), + const = true, + value = nil, + }, + { + "null", + word("NULL"), + const = true, + value = nil, + }, + { + "null", + word("~"), + const = true, + value = nil, + }, + { "id", '^"([^"]-)" *(:[%s%c])' }, + { "id", "^'([^']-)' *(:[%s%c])" }, + { "string", '^"([^"]-)"', force_text = true }, + { "string", "^'([^']-)'", force_text = true }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?):(%d%d)" }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?)" }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)" }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d)" }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?)" }, + { "timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)" }, + { "doc", "^%-%-%-[^%c]*" }, + { ",", "^," }, + { "string", "^%b{} *[^,%c]+", noinline = true }, + { "{", "^{" }, + { "}", "^}" }, + { "string", "^%b[] *[^,%c]+", noinline = true }, + { "[", "^%[" }, + { "]", "^%]" }, + { "-", "^%-", noinline = true }, + { ":", "^:" }, + { "pipe", "^(|)(%d*[+%-]?)", sep = "\n" }, + { "pipe", "^(>)(%d*[+%-]?)", sep = " " }, + { "id", "^([%w][%w %-_]*)(:[%s%c])" }, + { "string", "^[^%c]+", noinline = true }, + { "string", "^[^,%]}%c ]+" }, } exports.tokenize = function(str) - local token - local row = 0 - local ignore - local indents = 0 - local lastIndents - local stack = {} - local indentAmount = 0 - local inline = false - str = str:gsub("\r\n", "\010") - - while #str > 0 do - for i in ipairs(tokens) do - local captures = {} - if not inline or tokens[i].noinline == nil then - captures = { str:match(tokens[i][2]) } - end - - if #captures > 0 then - captures.input = str:sub(0, 25) - token = table_clone(tokens[i]) - token[2] = captures - local str2 = str:gsub(tokens[i][2], "", 1) - token.raw = str:sub(1, #str - #str2) - str = str2 - - if token[1] == "{" or token[1] == "[" then - inline = true - elseif token.const then - -- Since word pattern contains last char we're re-adding it - str = token[2][2] .. str - token.raw = token.raw:sub(1, #token.raw - #token[2][2]) - elseif token[1] == "id" then - -- Since id pattern contains last semi-colon we're re-adding it - str = token[2][2] .. str - token.raw = token.raw:sub(1, #token.raw - #token[2][2]) - -- Trim - token[2][1] = string_trim(token[2][1]) - elseif token[1] == "string" then - -- Finding numbers - local snip = token[2][1] - if not token.force_text then - if snip:match("^(-?%d+%.%d+)$") or snip:match("^(-?%d+)$") then - token[1] = "number" - end - end - elseif token[1] == "comment" then - ignore = true - elseif token[1] == "indent" then - row = row + 1 - inline = false - lastIndents = indents - if indentAmount == 0 then - indentAmount = #token[2][1] - end - - if indentAmount ~= 0 then - indents = (#token[2][1] / indentAmount) - else - indents = 0 - end - - if indents == lastIndents then - ignore = true - elseif indents > lastIndents + 2 then - error( - "SyntaxError: invalid indentation, got " - .. tostring(indents) - .. " instead of " - .. tostring(lastIndents) - .. context(token[2].input) - ) - elseif indents > lastIndents + 1 then - push(stack, token) - elseif indents < lastIndents then - local input = token[2].input - token = { "dedent", { "", input = "" } } - token.input = input - while lastIndents > indents + 1 do - lastIndents = lastIndents - 1 - push(stack, token) - end - end - end -- if token[1] == XXX - token.row = row - break - end -- if #captures > 0 - end - - if not ignore then - if token then - push(stack, token) - token = nil - else - error("SyntaxError " .. context(str)) - end - end - - ignore = false - end - - return stack + local token + local row = 0 + local ignore + local indents = 0 + local lastIndents + local stack = {} + local indentAmount = 0 + local inline = false + str = str:gsub("\r\n", "\010") + + while #str > 0 do + for i in ipairs(tokens) do + local captures = {} + if not inline or tokens[i].noinline == nil then + captures = { str:match(tokens[i][2]) } + end + + if #captures > 0 then + captures.input = str:sub(0, 25) + token = table_clone(tokens[i]) + token[2] = captures + local str2 = str:gsub(tokens[i][2], "", 1) + token.raw = str:sub(1, #str - #str2) + str = str2 + + if token[1] == "{" or token[1] == "[" then + inline = true + elseif token.const then + -- Since word pattern contains last char we're re-adding it + str = token[2][2] .. str + token.raw = token.raw:sub(1, #token.raw - #token[2][2]) + elseif token[1] == "id" then + -- Since id pattern contains last semi-colon we're re-adding it + str = token[2][2] .. str + token.raw = token.raw:sub(1, #token.raw - #token[2][2]) + -- Trim + token[2][1] = string_trim(token[2][1]) + elseif token[1] == "string" then + -- Finding numbers + local snip = token[2][1] + if not token.force_text then + if snip:match("^(-?%d+%.%d+)$") or snip:match("^(-?%d+)$") then + token[1] = "number" + end + end + elseif token[1] == "comment" then + ignore = true + elseif token[1] == "indent" then + row = row + 1 + inline = false + lastIndents = indents + if indentAmount == 0 then + indentAmount = #token[2][1] + end + + if indentAmount ~= 0 then + indents = (#token[2][1] / indentAmount) + else + indents = 0 + end + + if indents == lastIndents then + ignore = true + elseif indents > lastIndents + 2 then + error( + "SyntaxError: invalid indentation, got " + .. tostring(indents) + .. " instead of " + .. tostring(lastIndents) + .. context(token[2].input) + ) + elseif indents > lastIndents + 1 then + push(stack, token) + elseif indents < lastIndents then + local input = token[2].input + token = { "dedent", { "", input = "" } } + token.input = input + while lastIndents > indents + 1 do + lastIndents = lastIndents - 1 + push(stack, token) + end + end + end -- if token[1] == XXX + token.row = row + break + end -- if #captures > 0 + end + + if not ignore then + if token then + push(stack, token) + token = nil + else + error("SyntaxError " .. context(str)) + end + end + + ignore = false + end + + return stack end Parser.peek = function(self, offset) - offset = offset or 1 - return self.tokens[offset + self.current] + offset = offset or 1 + return self.tokens[offset + self.current] end Parser.advance = function(self) - self.current = self.current + 1 - return self.tokens[self.current] + self.current = self.current + 1 + return self.tokens[self.current] end Parser.advanceValue = function(self) - return self:advance()[2][1] + return self:advance()[2][1] end Parser.accept = function(self, type) - if self:peekType(type) then - return self:advance() - end + if self:peekType(type) then + return self:advance() + end end Parser.expect = function(self, type, msg) - return self:accept(type) or error(msg .. context(self:peek()[1].input)) + return self:accept(type) or error(msg .. context(self:peek()[1].input)) end Parser.expectDedent = function(self, msg) - return self:accept("dedent") or (self:peek() == nil) or error(msg .. context(self:peek()[2].input)) + return self:accept("dedent") or (self:peek() == nil) or error(msg .. context(self:peek()[2].input)) end Parser.peekType = function(self, val, offset) - return self:peek(offset) and self:peek(offset)[1] == val + return self:peek(offset) and self:peek(offset)[1] == val end Parser.ignore = function(self, items) - local advanced - repeat - advanced = false - for _, v in pairs(items) do - if self:peekType(v) then - self:advance() - advanced = true - end - end - until advanced == false + local advanced + repeat + advanced = false + for _, v in pairs(items) do + if self:peekType(v) then + self:advance() + advanced = true + end + end + until advanced == false end Parser.ignoreSpace = function(self) - self:ignore({ "space" }) + self:ignore({ "space" }) end Parser.ignoreWhitespace = function(self) - self:ignore({ "space", "indent", "dedent" }) + self:ignore({ "space", "indent", "dedent" }) end Parser.parse = function(self) - local ref = nil - if self:peekType("string") and not self:peek().force_text then - local char = self:peek()[2][1]:sub(1, 1) - if char == "&" then - ref = self:peek()[2][1]:sub(2) - self:advanceValue() - self:ignoreSpace() - elseif char == "*" then - ref = self:peek()[2][1]:sub(2) - return self.refs[ref] - end - end - - local result - local c = { - indent = self:accept("indent") and 1 or 0, - token = self:peek(), - } - push(self.parse_stack, c) - - if c.token[1] == "doc" then - result = self:parseDoc() - elseif c.token[1] == "-" then - result = self:parseList() - elseif c.token[1] == "{" then - result = self:parseInlineHash() - elseif c.token[1] == "[" then - result = self:parseInlineList() - elseif c.token[1] == "id" then - result = self:parseHash() - elseif c.token[1] == "string" then - result = self:parseString("\n") - elseif c.token[1] == "timestamp" then - result = self:parseTimestamp() - elseif c.token[1] == "number" then - result = tonumber(self:advanceValue()) - elseif c.token[1] == "pipe" then - result = self:parsePipe() - elseif c.token.const == true then - self:advanceValue() - result = c.token.value - else - error("ParseError: unexpected token '" .. c.token[1] .. "'" .. context(c.token.input)) - end - - pop(self.parse_stack) - while c.indent > 0 do - c.indent = c.indent - 1 - local term = "term " .. c.token[1] .. ": '" .. c.token[2][1] .. "'" - self:expectDedent("last " .. term .. " is not properly dedented") - end - - if ref then - self.refs[ref] = result - end - return result + local ref = nil + if self:peekType("string") and not self:peek().force_text then + local char = self:peek()[2][1]:sub(1, 1) + if char == "&" then + ref = self:peek()[2][1]:sub(2) + self:advanceValue() + self:ignoreSpace() + elseif char == "*" then + ref = self:peek()[2][1]:sub(2) + return self.refs[ref] + end + end + + local result + local c = { + indent = self:accept("indent") and 1 or 0, + token = self:peek(), + } + push(self.parse_stack, c) + + if c.token[1] == "doc" then + result = self:parseDoc() + elseif c.token[1] == "-" then + result = self:parseList() + elseif c.token[1] == "{" then + result = self:parseInlineHash() + elseif c.token[1] == "[" then + result = self:parseInlineList() + elseif c.token[1] == "id" then + result = self:parseHash() + elseif c.token[1] == "string" then + result = self:parseString("\n") + elseif c.token[1] == "timestamp" then + result = self:parseTimestamp() + elseif c.token[1] == "number" then + result = tonumber(self:advanceValue()) + elseif c.token[1] == "pipe" then + result = self:parsePipe() + elseif c.token.const == true then + self:advanceValue() + result = c.token.value + else + error("ParseError: unexpected token '" .. c.token[1] .. "'" .. context(c.token.input)) + end + + pop(self.parse_stack) + while c.indent > 0 do + c.indent = c.indent - 1 + local term = "term " .. c.token[1] .. ": '" .. c.token[2][1] .. "'" + self:expectDedent("last " .. term .. " is not properly dedented") + end + + if ref then + self.refs[ref] = result + end + return result end Parser.parseDoc = function(self) - self:accept("doc") - return self:parse() + self:accept("doc") + return self:parse() end Parser.inline = function(self) - local current = self:peek(0) - if not current then - return {}, 0 - end + local current = self:peek(0) + if not current then + return {}, 0 + end - local inline = {} - local i = 0 + local inline = {} + local i = 0 - while self:peek(i) and not self:peekType("indent", i) and current.row == self:peek(i).row do - inline[self:peek(i)[1]] = true - i = i - 1 - end - return inline, -i + while self:peek(i) and not self:peekType("indent", i) and current.row == self:peek(i).row do + inline[self:peek(i)[1]] = true + i = i - 1 + end + return inline, -i end Parser.isInline = function(self) - local _, i = self:inline() - return i > 0 + local _, i = self:inline() + return i > 0 end Parser.parent = function(self, level) - level = level or 1 - return self.parse_stack[#self.parse_stack - level] + level = level or 1 + return self.parse_stack[#self.parse_stack - level] end Parser.parentType = function(self, type, level) - return self:parent(level) and self:parent(level).token[1] == type + return self:parent(level) and self:parent(level).token[1] == type end Parser.parseString = function(self) - if self:isInline() then - local result = self:advanceValue() + if self:isInline() then + local result = self:advanceValue() - --[[ + --[[ - a: this looks flowing: but is no: string --]] - local types = self:inline() - if types["id"] and types["-"] then - if not self:peekType("indent") or not self:peekType("indent", 2) then - return result - end - end - - --[[ + local types = self:inline() + if types["id"] and types["-"] then + if not self:peekType("indent") or not self:peekType("indent", 2) then + return result + end + end + + --[[ a: 1 b: this is a flowing string example c: 3 --]] - if self:peekType("indent") then - self:expect("indent", "text block needs to start with indent") - local addtl = self:accept("indent") - - result = result .. "\n" .. self:parseTextBlock("\n") - - self:expectDedent("text block ending dedent missing") - if addtl then - self:expectDedent("text block ending dedent missing") - end - end - return result - else - --[[ + if self:peekType("indent") then + self:expect("indent", "text block needs to start with indent") + local addtl = self:accept("indent") + + result = result .. "\n" .. self:parseTextBlock("\n") + + self:expectDedent("text block ending dedent missing") + if addtl then + self:expectDedent("text block ending dedent missing") + end + end + return result + else + --[[ a: 1 b: this is also @@ -497,149 +497,149 @@ Parser.parseString = function(self) example c: 3 --]] - return self:parseTextBlock("\n") - end + return self:parseTextBlock("\n") + end end Parser.parsePipe = function(self) - local pipe = self:expect("pipe") - self:expect("indent", "text block needs to start with indent") - local result = self:parseTextBlock(pipe.sep) - self:expectDedent("text block ending dedent missing") - return result + local pipe = self:expect("pipe") + self:expect("indent", "text block needs to start with indent") + local result = self:parseTextBlock(pipe.sep) + self:expectDedent("text block ending dedent missing") + return result end Parser.parseTextBlock = function(self, sep) - local token = self:advance() - local result = string_trim(token.raw, "\n") - local indents = 0 - while self:peek() ~= nil and (indents > 0 or not self:peekType("dedent")) do - local newtoken = self:advance() - while token.row < newtoken.row do - result = result .. sep - token.row = token.row + 1 - end - if newtoken[1] == "indent" then - indents = indents + 1 - elseif newtoken[1] == "dedent" then - indents = indents - 1 - else - result = result .. string_trim(newtoken.raw, "\n") - end - end - return result + local token = self:advance() + local result = string_trim(token.raw, "\n") + local indents = 0 + while self:peek() ~= nil and (indents > 0 or not self:peekType("dedent")) do + local newtoken = self:advance() + while token.row < newtoken.row do + result = result .. sep + token.row = token.row + 1 + end + if newtoken[1] == "indent" then + indents = indents + 1 + elseif newtoken[1] == "dedent" then + indents = indents - 1 + else + result = result .. string_trim(newtoken.raw, "\n") + end + end + return result end Parser.parseHash = function(self, hash) - hash = hash or {} - local indents = 0 - - if self:isInline() then - local id = self:advanceValue() - self:expect(":", "expected semi-colon after id") - self:ignoreSpace() - if self:accept("indent") then - indents = indents + 1 - hash[id] = self:parse() - else - hash[id] = self:parse() - if self:accept("indent") then - indents = indents + 1 - end - end - self:ignoreSpace() - end - - while self:peekType("id") do - local id = self:advanceValue() - self:expect(":", "expected semi-colon after id") - self:ignoreSpace() - hash[id] = self:parse() - self:ignoreSpace() - end - - while indents > 0 do - self:expectDedent("expected dedent") - indents = indents - 1 - end - - return hash + hash = hash or {} + local indents = 0 + + if self:isInline() then + local id = self:advanceValue() + self:expect(":", "expected semi-colon after id") + self:ignoreSpace() + if self:accept("indent") then + indents = indents + 1 + hash[id] = self:parse() + else + hash[id] = self:parse() + if self:accept("indent") then + indents = indents + 1 + end + end + self:ignoreSpace() + end + + while self:peekType("id") do + local id = self:advanceValue() + self:expect(":", "expected semi-colon after id") + self:ignoreSpace() + hash[id] = self:parse() + self:ignoreSpace() + end + + while indents > 0 do + self:expectDedent("expected dedent") + indents = indents - 1 + end + + return hash end Parser.parseInlineHash = function(self) - local id - local hash = {} - local i = 0 - - self:accept("{") - while not self:accept("}") do - self:ignoreSpace() - if i > 0 then - self:expect(",", "expected comma") - end - - self:ignoreWhitespace() - if self:peekType("id") then - id = self:advanceValue() - if id then - self:expect(":", "expected semi-colon after id") - self:ignoreSpace() - hash[id] = self:parse() - self:ignoreWhitespace() - end - end - - i = i + 1 - end - return hash + local id + local hash = {} + local i = 0 + + self:accept("{") + while not self:accept("}") do + self:ignoreSpace() + if i > 0 then + self:expect(",", "expected comma") + end + + self:ignoreWhitespace() + if self:peekType("id") then + id = self:advanceValue() + if id then + self:expect(":", "expected semi-colon after id") + self:ignoreSpace() + hash[id] = self:parse() + self:ignoreWhitespace() + end + end + + i = i + 1 + end + return hash end Parser.parseList = function(self) - local list = {} - while self:accept("-") do - self:ignoreSpace() - list[#list + 1] = self:parse() + local list = {} + while self:accept("-") do + self:ignoreSpace() + list[#list + 1] = self:parse() - self:ignoreSpace() - end - return list + self:ignoreSpace() + end + return list end Parser.parseInlineList = function(self) - local list = {} - local i = 0 - self:accept("[") - while not self:accept("]") do - self:ignoreSpace() - if i > 0 then - self:expect(",", "expected comma") - end + local list = {} + local i = 0 + self:accept("[") + while not self:accept("]") do + self:ignoreSpace() + if i > 0 then + self:expect(",", "expected comma") + end - self:ignoreSpace() - list[#list + 1] = self:parse() - self:ignoreSpace() - i = i + 1 - end + self:ignoreSpace() + list[#list + 1] = self:parse() + self:ignoreSpace() + i = i + 1 + end - return list + return list end Parser.parseTimestamp = function(self) - local capture = self:advance()[2] + local capture = self:advance()[2] - return os.time({ - year = capture[1], - month = capture[2], - day = capture[3], - hour = capture[4] or 0, - min = capture[5] or 0, - sec = capture[6] or 0, - isdst = false, - }) - os.time({ year = 1970, month = 1, day = 1, hour = 8 }) + return os.time({ + year = capture[1], + month = capture[2], + day = capture[3], + hour = capture[4] or 0, + min = capture[5] or 0, + sec = capture[6] or 0, + isdst = false, + }) - os.time({ year = 1970, month = 1, day = 1, hour = 8 }) end exports.eval = function(str) - return Parser:new(exports.tokenize(str)):parse() + return Parser:new(exports.tokenize(str)):parse() end exports.dump = table_print diff --git a/lua/cmake/telescope/pickers.lua b/lua/cmake/telescope/pickers.lua index c543df8..c82de90 100644 --- a/lua/cmake/telescope/pickers.lua +++ b/lua/cmake/telescope/pickers.lua @@ -9,94 +9,94 @@ local previewers = require("cmake.telescope.previewers") local M = {} M.build_dirs = function(opts) - local cmake = require("cmake") - pickers - .new(opts, { - prompt_title = "CMake Builds", - finder = finders.new_table({ - results = cmake.project.fileapis, - -- entry_maker = cmake_make_entry.gen_from_fileapi(opts), - entry_maker = function(entry) - return { - value = entry, - display = entry.path, - ordinal = entry.path, - } - end, - sorter = conf.generic_sorter(opts), - -- attach_mappings = function(prompt_bufnr, map) - -- actions.select_default:replace(function() end) - -- return true - -- end, - }), - }) - :find() + local cmake = require("cmake") + pickers + .new(opts, { + prompt_title = "CMake Builds", + finder = finders.new_table({ + results = cmake.project.fileapis, + -- entry_maker = cmake_make_entry.gen_from_fileapi(opts), + entry_maker = function(entry) + return { + value = entry, + display = entry.path, + ordinal = entry.path, + } + end, + sorter = conf.generic_sorter(opts), + -- attach_mappings = function(prompt_bufnr, map) + -- actions.select_default:replace(function() end) + -- return true + -- end, + }), + }) + :find() end M.configure = function(opts) - local cmake = require("cmake") - local runner = require("cmake.runner") - opts.layout_strategy = "vertical" - opts.layout_config = { - prompt_position = "top", - preview_cutoff = 0, - preview_height = 5, - mirror = true, - } - pickers - .new(opts, { - default_selection_index = cmake.project:current_configure_index(), - prompt_title = "CMake Configure Options", - finder = finders.new_table({ - results = cmake.project:list_configs(), - entry_maker = cmake_make_entry.gen_from_configure(opts), - }), - sorter = conf.generic_sorter(opts), - previewer = previewers.configure_previewer(), - attach_mappings = function(prompt_bufnr, map) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - cmake.project.current_config = selection.value - runner.start(selection.value.generate_command) - end) - return true - end, - }) - :find() + local cmake = require("cmake") + local runner = require("cmake.runner") + opts.layout_strategy = "vertical" + opts.layout_config = { + prompt_position = "top", + preview_cutoff = 0, + preview_height = 5, + mirror = true, + } + pickers + .new(opts, { + default_selection_index = cmake.project:current_configure_index(), + prompt_title = "CMake Configure Options", + finder = finders.new_table({ + results = cmake.project:list_configs(), + entry_maker = cmake_make_entry.gen_from_configure(opts), + }), + sorter = conf.generic_sorter(opts), + previewer = previewers.configure_previewer(), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + cmake.project.current_config = selection.value + runner.start(selection.value.generate_command) + end) + return true + end, + }) + :find() end M.build = function(opts) - local cmake = require("cmake") - local runner = require("cmake.runner") - opts.layout_strategy = "vertical" - opts.layout_config = { - prompt_position = "top", - preview_cutoff = 0, - preview_height = 5, - mirror = true, - } - pickers - .new(opts, { - default_selection_index = cmake.project:current_build_index(), - prompt_title = "CMake Build Options", - finder = finders.new_table({ - results = cmake.project:list_builds(), - entry_maker = cmake_make_entry.gen_from_configure(opts), - }), - sorter = conf.generic_sorter(opts), - previewer = previewers.build_previewer(), - attach_mappings = function(prompt_bufnr, map) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - cmake.project.current_config = selection.value - runner.start(selection.value.build_command) - end) - return true - end, - }) - :find() + local cmake = require("cmake") + local runner = require("cmake.runner") + opts.layout_strategy = "vertical" + opts.layout_config = { + prompt_position = "top", + preview_cutoff = 0, + preview_height = 5, + mirror = true, + } + pickers + .new(opts, { + default_selection_index = cmake.project:current_build_index(), + prompt_title = "CMake Build Options", + finder = finders.new_table({ + results = cmake.project:list_builds(), + entry_maker = cmake_make_entry.gen_from_configure(opts), + }), + sorter = conf.generic_sorter(opts), + previewer = previewers.build_previewer(), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + cmake.project.current_config = selection.value + runner.start(selection.value.build_command) + end) + return true + end, + }) + :find() end return M diff --git a/lua/cmake/terminal.lua b/lua/cmake/terminal.lua index 689590f..c6bb533 100644 --- a/lua/cmake/terminal.lua +++ b/lua/cmake/terminal.lua @@ -5,116 +5,113 @@ local api = vim.api local M = {} local cmake = { - bufnr = nil, - window = nil, - jobid = nil, + bufnr = nil, + window = nil, + jobid = nil, } local runnable local scroll_to_bottom = function() - local info = vim.api.nvim_get_mode() - if info and (info.mode == "n" or info.mode == "nt") then - vim.cmd("normal! G") - end + local info = vim.api.nvim_get_mode() + if info and (info.mode == "n" or info.mode == "nt") then + vim.cmd("normal! G") + end end local prepare_cmake_buf = function() - if cmake.bufnr and api.nvim_buf_is_valid(cmake.bufnr) then - api.nvim_buf_delete(cmake.bufnr, { force = true }) - end - cmake.bufnr = api.nvim_create_buf(false, false) + if cmake.bufnr and api.nvim_buf_is_valid(cmake.bufnr) then + api.nvim_buf_delete(cmake.bufnr, { force = true }) + end + cmake.bufnr = api.nvim_create_buf(false, false) end local termopen = function(command, opts) - -- For some reason termopen() doesn't like an empty env table - if command.env and vim.tbl_isempty(command.env) then - command.env = nil - end - vim.fn.termopen(command.cmd .. " " .. command.args, { - -- detach = 1, - cwd = command.cwd, - env = command.env, - clear_env = config.cmake_terminal.clear_env, - on_stdout = function(_, data, _) - api.nvim_buf_call(cmake.bufnr, scroll_to_bottom) - end, - on_exit = function(pid, code, event) - if code == 0 then - command.after_success() - if config.cmake_terminal.close_on_exit == "success" or config.cmake_terminal.close_on_exit == true then - if api.nvim_win_is_valid(cmake.window) then - api.nvim_win_close(cmake.window, true) - end - end - if config.notification.after == "success" or config.notification.after == true then - vim.notify( - vim.tbl_get(opts, "notify", "ok_message") or "CMake successfully completed", - vim.log.levels.INFO - ) - end - else - if config.notification.after == "failure" or config.notification.after == true then - local msg = "CMake failed. Code " .. tostring(code) - local opt_msg = vim.tbl_get(opts, "notify", "err_message") - if type(opt_msg) == "string" then - msg = opt_msg - elseif type(opt_msg) == "function" then - msg = opt_msg(code) - end - vim.notify(msg, vim.log.levels.ERROR) - end - end - end, - }) + -- For some reason termopen() doesn't like an empty env table + if command.env and vim.tbl_isempty(command.env) then + command.env = nil + end + vim.fn.termopen(command.cmd .. " " .. command.args, { + -- detach = 1, + cwd = command.cwd, + env = command.env, + clear_env = config.cmake_terminal.clear_env, + on_stdout = function(_, data, _) + api.nvim_buf_call(cmake.bufnr, scroll_to_bottom) + end, + on_exit = function(pid, code, event) + if code == 0 then + command.after_success() + if config.cmake_terminal.close_on_exit == "success" or config.cmake_terminal.close_on_exit == true then + if api.nvim_win_is_valid(cmake.window) then + api.nvim_win_close(cmake.window, true) + end + end + if config.notification.after == "success" or config.notification.after == true then + vim.notify(vim.tbl_get(opts, "notify", "ok_message") or "CMake successfully completed", vim.log.levels.INFO) + end + else + if config.notification.after == "failure" or config.notification.after == true then + local msg = "CMake failed. Code " .. tostring(code) + local opt_msg = vim.tbl_get(opts, "notify", "err_message") + if type(opt_msg) == "string" then + msg = opt_msg + elseif type(opt_msg) == "function" then + msg = opt_msg(code) + end + vim.notify(msg, vim.log.levels.ERROR) + end + end + end, + }) end local open_window = function() - if not cmake.bufnr then - vim.notify("No CMake buffer created yet", vim.log.levels.INFO) - return - end - cmake.window = api.nvim_open_win(cmake.bufnr, config.cmake_terminal.enter, { - win = 0, - split = config.cmake_terminal.split, - height = config.cmake_terminal.size, - width = config.cmake_terminal.size, - }) + if not cmake.bufnr then + vim.notify("No CMake buffer created yet", vim.log.levels.INFO) + return + end + cmake.window = api.nvim_open_win(cmake.bufnr, config.cmake_terminal.enter, { + win = 0, + split = config.cmake_terminal.split, + height = config.cmake_terminal.size, + width = config.cmake_terminal.size, + }) end M.cmake_execute = function(command, opts) - opts = opts or {} + opts = opts or {} - prepare_cmake_buf() - if config.cmake_terminal.open_on_start and not (cmake.window and api.nvim_win_is_valid(cmake.window)) then - open_window() - end - vim.api.nvim_buf_call(cmake.bufnr, function() - termopen(command, opts) - end) + prepare_cmake_buf() + if config.cmake_terminal.open_on_start and not (cmake.window and api.nvim_win_is_valid(cmake.window)) then + open_window() + end + vim.api.nvim_buf_call(cmake.bufnr, function() + termopen(command, opts) + end) end M.cmake_toggle = function() - if cmake.window and api.nvim_win_is_valid(cmake.window) then - api.nvim_win_close(cmake.window, true) - else - open_window() - end + if cmake.window and api.nvim_win_is_valid(cmake.window) then + api.nvim_win_close(cmake.window, true) + else + open_window() + end end M.target_execute = function(command, opts) - opts = opts or {} - local bufnr = api.nvim_create_buf(true, false) - api.nvim_open_win(bufnr, config.target_terminal.enter, { - win = 0, - split = config.target_terminal.split, - height = config.target_terminal.size, - width = config.target_terminal.size, - }) - api.nvim_buf_call(bufnr, function() - vim.cmd.terminal() - api.nvim_chan_send(vim.bo.channel, command.cwd .. "/" .. command.cmd) - end) + opts = opts or {} + local bufnr = api.nvim_create_buf(true, false) + api.nvim_open_win(bufnr, config.target_terminal.enter, { + win = 0, + split = config.target_terminal.split, + height = config.target_terminal.size, + width = config.target_terminal.size, + }) + api.nvim_buf_call(bufnr, function() + vim.cmd.terminal() + api.nvim_chan_send(vim.bo.channel, command.cwd .. "/" .. command.cmd) + end) end return M diff --git a/lua/cmake/utils.lua b/lua/cmake/utils.lua index ce6d213..9e40aa4 100644 --- a/lua/cmake/utils.lua +++ b/lua/cmake/utils.lua @@ -4,102 +4,102 @@ local uv = vim.uv local utils = {} utils.substitude = function(str, subs) - local ret = str - for k, v in pairs(subs) do - ret = ret:gsub(k, v) - end - return ret + local ret = str + for k, v in pairs(subs) do + ret = ret:gsub(k, v) + end + return ret end function utils.touch_file(path, txt, flag, callback) - uv.fs_open(path, flag, 438, function(err, fd) - assert(not err, err) - assert(fd) - uv.fs_close(fd, function(c_err) - assert(not c_err, c_err) - if type(callback) == "function" then - callback() - end - end) - end) + uv.fs_open(path, flag, 438, function(err, fd) + assert(not err, err) + assert(fd) + uv.fs_close(fd, function(c_err) + assert(not c_err, c_err) + if type(callback) == "function" then + callback() + end + end) + end) end function utils.file_exists(path, callback) - uv.fs_stat(path, function(err, _) - local exists - if err then - exists = false - else - exists = true - end - if type(callback) == "function" then - callback(exists) - end - end) + uv.fs_stat(path, function(err, _) + local exists + if err then + exists = false + else + exists = true + end + if type(callback) == "function" then + callback(exists) + end + end) end function utils.read_file(path, callback) - uv.fs_open(path, "r", 438, function(err, fd) - assert(not err, err) - assert(fd, fd) - uv.fs_fstat(fd, function(s_err, stat) - assert(not s_err, s_err) - assert(stat, stat) - uv.fs_read(fd, stat.size, 0, function(r_err, data) - assert(not r_err, r_err) - uv.fs_close(fd, function(c_err) - assert(not c_err, c_err) - callback(data) - end) - end) - end) - end) + uv.fs_open(path, "r", 438, function(err, fd) + assert(not err, err) + assert(fd, fd) + uv.fs_fstat(fd, function(s_err, stat) + assert(not s_err, s_err) + assert(stat, stat) + uv.fs_read(fd, stat.size, 0, function(r_err, data) + assert(not r_err, r_err) + uv.fs_close(fd, function(c_err) + assert(not c_err, c_err) + callback(data) + end) + end) + end) + end) end function utils.read_file_sync(path) - local fd = assert(vim.uv.fs_open(path, "r", 438)) - local stat = assert(vim.uv.fs_fstat(fd)) - local data = assert(vim.uv.fs_read(fd, stat.size, 0)) - assert(vim.uv.fs_close(fd)) - return data + local fd = assert(vim.uv.fs_open(path, "r", 438)) + local stat = assert(vim.uv.fs_fstat(fd)) + local data = assert(vim.uv.fs_read(fd, stat.size, 0)) + assert(vim.uv.fs_close(fd)) + return data end function utils.write_file(path, txt, callback) - uv.fs_open(path, "w", 438, function(err, fd) - assert(not err, err) - assert(fd) - uv.fs_write(fd, txt, nil, function(w_err, _) - assert(not w_err, w_err) - uv.fs_close(fd, function(c_err) - assert(not c_err, c_err) - if type(callback) == "function" then - callback() - end - end) - end) - end) + uv.fs_open(path, "w", 438, function(err, fd) + assert(not err, err) + assert(fd) + uv.fs_write(fd, txt, nil, function(w_err, _) + assert(not w_err, w_err) + uv.fs_close(fd, function(c_err) + assert(not c_err, c_err) + if type(callback) == "function" then + callback() + end + end) + end) + end) end function utils.symlink(src_path, dst_path, callback) - local src = vim.fs.joinpath(src_path, "compile_commands.json") - utils.file_exists(src, function() - uv.spawn(config.cmake.cmake_path, { - args = { - "-E", - "create_symlink", - src, - vim.fs.joinpath(dst_path, "compile_commands.json"), - }, - }, function(code, signal) - if code ~= 0 then - vim.notify("CMake: error while creating symlink. Code " .. tostring(code), vim.log.levels.ERROR) - return - end - if type(callback) == "function" then - callback() - end - end) - end) + local src = vim.fs.joinpath(src_path, "compile_commands.json") + utils.file_exists(src, function() + uv.spawn(config.cmake.cmake_path, { + args = { + "-E", + "create_symlink", + src, + vim.fs.joinpath(dst_path, "compile_commands.json"), + }, + }, function(code, signal) + if code ~= 0 then + vim.notify("CMake: error while creating symlink. Code " .. tostring(code), vim.log.levels.ERROR) + return + end + if type(callback) == "function" then + callback() + end + end) + end) end return utils diff --git a/lua/cmake/variants.lua b/lua/cmake/variants.lua index cb846e8..ce7d8a7 100644 --- a/lua/cmake/variants.lua +++ b/lua/cmake/variants.lua @@ -8,155 +8,155 @@ local VariantConfig = {} VariantConfig.__index = VariantConfig local global_variant_subs = { - ["${workspaceFolder}"] = uv.cwd(), - ["${userHome}"] = uv.os_homedir(), + ["${workspaceFolder}"] = uv.cwd(), + ["${userHome}"] = uv.os_homedir(), } local _configure_args = function(obj, build_directory) - local args = {} - if obj.generator then - table.insert(args, "-G " .. '"' .. obj.generator .. '"') - end - table.insert(args, "-B" .. build_directory) - if obj.buildType then - table.insert(args, "-DCMAKE_BUILD_TYPE=" .. obj.buildType) - end - if obj.linkage and string.lower(obj.linkage) == "static" then - table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=OFF") - elseif obj.linkage and string.lower(obj.linkage) == "shared" then - table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=ON") - end - for k, v in pairs(obj.settings or {}) do - table.insert(args, "-D" .. k .. "=" .. v) - end - table.insert(args, "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON") - return args + local args = {} + if obj.generator then + table.insert(args, "-G " .. '"' .. obj.generator .. '"') + end + table.insert(args, "-B" .. build_directory) + if obj.buildType then + table.insert(args, "-DCMAKE_BUILD_TYPE=" .. obj.buildType) + end + if obj.linkage and string.lower(obj.linkage) == "static" then + table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=OFF") + elseif obj.linkage and string.lower(obj.linkage) == "shared" then + table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=ON") + end + for k, v in pairs(obj.settings or {}) do + table.insert(args, "-D" .. k .. "=" .. v) + end + table.insert(args, "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON") + return args end local _configure_command = function(obj, configure_args) - local ret = {} - ret.cmd = config.cmake.cmake_path - ret.args = table.concat(configure_args, " ") - ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment) - return ret + local ret = {} + ret.cmd = config.cmake.cmake_path + ret.args = table.concat(configure_args, " ") + ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment) + return ret end local _build_args = function(obj, build_directory) - local args = { "--build" } - table.insert(args, build_directory) - if config.cmake.parallel_jobs then - table.insert(args, "-j " .. tostring(config.cmake.parallel_jobs)) - end - if #obj.buildArgs ~= 0 then - for _, v in ipairs(obj.buildArgs) do - table.insert(args, v) - end - elseif #config.cmake.build_args ~= 0 then - for _, v in ipairs(config.cmake.build_args) do - table.insert(args, v) - end - end - if #obj.buildToolArgs ~= 0 or #config.cmake.build_tool_args ~= 0 then - table.insert(args, "--") - if #obj.buildToolArgs ~= 0 then - for _, v in ipairs(obj.buildToolArgs) do - table.insert(args, v) - end - elseif #config.cmake.build_tool_args ~= 0 then - for _, v in ipairs(config.cmake.build_tool_args) do - table.insert(args, v) - end - end - end - return args + local args = { "--build" } + table.insert(args, build_directory) + if config.cmake.parallel_jobs then + table.insert(args, "-j " .. tostring(config.cmake.parallel_jobs)) + end + if #obj.buildArgs ~= 0 then + for _, v in ipairs(obj.buildArgs) do + table.insert(args, v) + end + elseif #config.cmake.build_args ~= 0 then + for _, v in ipairs(config.cmake.build_args) do + table.insert(args, v) + end + end + if #obj.buildToolArgs ~= 0 or #config.cmake.build_tool_args ~= 0 then + table.insert(args, "--") + if #obj.buildToolArgs ~= 0 then + for _, v in ipairs(obj.buildToolArgs) do + table.insert(args, v) + end + elseif #config.cmake.build_tool_args ~= 0 then + for _, v in ipairs(config.cmake.build_tool_args) do + table.insert(args, v) + end + end + end + return args end local _build_command = function(obj, build_args) - local ret = {} - ret.cmd = config.cmake.cmake_path - ret.args = table.concat(build_args, " ") - ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment) - return ret + local ret = {} + ret.cmd = config.cmake.cmake_path + ret.args = table.concat(build_args, " ") + ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment) + return ret end ---Create configuration from variant ---@param source table ---@return CMakeGenerateOption function VariantConfig:new(source) - local obj = {} - local subs = vim.tbl_deep_extend("keep", global_variant_subs, { ["${buildType}"] = source.buildType }) + local obj = {} + local subs = vim.tbl_deep_extend("keep", global_variant_subs, { ["${buildType}"] = source.buildType }) - obj.name = source.short - obj.long_name = source.long - obj.directory = utils.substitude(config.cmake.build_directory, subs) - local configure_args = _configure_args(source, obj.directory) - obj.generate_command = _configure_command(source, configure_args) - local build_args = _build_args(source, obj.directory) - obj.build_options = { - { - name = source.short, - long_name = source.long, - command = _build_command(source, build_args), - }, - } + obj.name = source.short + obj.long_name = source.long + obj.directory = utils.substitude(config.cmake.build_directory, subs) + local configure_args = _configure_args(source, obj.directory) + obj.generate_command = _configure_command(source, configure_args) + local build_args = _build_args(source, obj.directory) + obj.build_options = { + { + name = source.short, + long_name = source.long, + command = _build_command(source, build_args), + }, + } - setmetatable(obj, VariantConfig) - return obj + setmetatable(obj, VariantConfig) + return obj end function VariantConfig.cartesian_product(sets) - local function collapse_result(res) - local ret = { - short = {}, - long = {}, - buildType = nil, - linkage = nil, - generator = nil, - buildArgs = {}, - buildToolArgs = {}, - settings = {}, - env = {}, - } - local is_default = true - for _, v in ipairs(res) do - if not v.default then - is_default = false - end - ret.short[#ret.short + 1] = v.short - ret.long[#ret.long + 1] = v.long - ret.buildType = v.buildType or ret.buildType - ret.linkage = v.linkage or ret.linkage - ret.generator = v.generator or ret.generator - ret.buildArgs = v.buildArgs or ret.buildArgs - ret.buildToolArgs = v.buildToolArgs or ret.buildToolArgs - for sname, sval in pairs(v.settings or {}) do - ret.settings[sname] = sval - end - for ename, eres in pairs(v.env or {}) do - ret.env[ename] = eres - end - end - return VariantConfig:new(ret), is_default - end - local result = {} - local set_count = #sets - local function descend(depth) - for k, v in pairs(sets[depth].choices) do - if sets[depth].default ~= k then - result.default = false - end - result[depth] = v - result[depth].default = (k == sets[depth].default) - if depth == set_count then - coroutine.yield(collapse_result(result)) - else - descend(depth + 1) - end - end - end - return coroutine.wrap(function() - descend(1) - end) + local function collapse_result(res) + local ret = { + short = {}, + long = {}, + buildType = nil, + linkage = nil, + generator = nil, + buildArgs = {}, + buildToolArgs = {}, + settings = {}, + env = {}, + } + local is_default = true + for _, v in ipairs(res) do + if not v.default then + is_default = false + end + ret.short[#ret.short + 1] = v.short + ret.long[#ret.long + 1] = v.long + ret.buildType = v.buildType or ret.buildType + ret.linkage = v.linkage or ret.linkage + ret.generator = v.generator or ret.generator + ret.buildArgs = v.buildArgs or ret.buildArgs + ret.buildToolArgs = v.buildToolArgs or ret.buildToolArgs + for sname, sval in pairs(v.settings or {}) do + ret.settings[sname] = sval + end + for ename, eres in pairs(v.env or {}) do + ret.env[ename] = eres + end + end + return VariantConfig:new(ret), is_default + end + local result = {} + local set_count = #sets + local function descend(depth) + for k, v in pairs(sets[depth].choices) do + if sets[depth].default ~= k then + result.default = false + end + result[depth] = v + result[depth].default = (k == sets[depth].default) + if depth == set_count then + coroutine.yield(collapse_result(result)) + else + descend(depth + 1) + end + end + end + return coroutine.wrap(function() + descend(1) + end) end return VariantConfig -- cgit v1.2.3