Skip to content
This repository was archived by the owner on Apr 16, 2024. It is now read-only.

traverser #419

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
79 changes: 49 additions & 30 deletions lua/doom/core/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,40 +63,59 @@ config.load = function()
local enabled_modules = require("doom.core.modules").enabled_modules

profiler.start("framework|import modules")
-- Iterate over each module and save it to the doom global object
for section_name, section_modules in pairs(enabled_modules) do
for _, module_name in pairs(section_modules) do
-- If the section is `user` resolves from `lua/user/modules`
local profiler_message = ("modules|import `%s.%s`"):format(section_name, module_name)
profiler.start(profiler_message)
local search_paths = {
("user.modules.%s.%s"):format(section_name, module_name),
("doom.modules.%s.%s"):format(section_name, module_name),
}

local ok, result
for _, path in ipairs(search_paths) do
ok, result = xpcall(require, debug.traceback, path)
if ok then
break

-- Combine enabled modules (`modules.lua`) with core modules.
require("doom.utils.modules").traverse_enabled(
enabled_modules,
function(node, stack)
if type(node) == "string" then
local t_path = vim.tbl_map(function(stack_node)
return type(stack_node.key) == "string" and stack_node.key or stack_node.node
end, stack)

local path_module = table.concat(t_path, ".")

local profiler_message = ("modules|import `%s`"):format(path_module)
profiler.start(profiler_message)

-- If the section is `user` resolves from `lua/user/modules`
local search_paths = {
("user.modules.%s"):format(path_module),
("doom.modules.%s"):format(path_module),
}

local ok, result
for _, path in ipairs(search_paths) do
ok, result = xpcall(require, debug.traceback, path)
if ok then
break
end
end
end
if ok then
doom[section_name][module_name] = result
else
local log = require("doom.utils.logging")
log.error(
string.format(
"There was an error loading module '%s.%s'. Traceback:\n%s",
section_name,
module_name,
result

if ok then
-- Add string tag so that we can easilly target modules with more
-- traversers, ie. in `core/modules` when traversing `doom.modules`
result.type = "doom_module_single"
utils.get_set_table_path(doom.modules, t_path, result)
else
local log = require("doom.utils.logging")
log.error(
string.format(
"There was an error loading module '%s'. Traceback:\n%s",
path_module,
result
)
)
)
end

profiler.stop(profiler_message)
end
profiler.stop(profiler_message)
end
end
, { debug = doom.logging == "trace" or doom.logging == "debug" }
)



profiler.stop("framework|import modules")

profiler.start("framework|config.lua (user)")
Expand Down
38 changes: 20 additions & 18 deletions lua/doom/core/modules.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ local autocmds_service = require("doom.services.autocommands")
--- Applies commands, autocommands, packages from enabled modules (`modules.lua`).
modules.load_modules = function()
local logger = require("doom.utils.logging")

-- Handle the Modules
for section_name, _ in pairs(doom.modules) do
for module_name, module in pairs(doom.modules[section_name]) do
if type(module) ~= "table" then
print(("Error on module %s type is %s val is %s"):format(module_name, type(module), module))
end
local profile_msg = ("modules|init `%s.%s`"):format(section_name, module_name)
require("doom.utils.modules").traverse_loaded(doom.modules, function(node, stack)
if node.type then
local module = node
local t_path = vim.tbl_map(function(stack_node)
return type(stack_node.key) == "string" and stack_node.key
end, stack)
local path_module = table.concat(t_path, ".")
local profile_msg = ("modules|init `%s`"):format(path_module)
profiler.start(profile_msg)

-- Flag to continue enabling module
Expand All @@ -53,17 +56,13 @@ modules.load_modules = function()
-- Check module has necessary dependencies
if module.requires_modules then
for _, dependent_module in ipairs(module.requires_modules) do
local dep_section_name, dep_module_name = unpack(vim.split(dependent_module, "%."))

if not doom.modules[dep_section_name][dep_module_name] then
if not utils.get_set_table_path(doom.modules, vim.split(dependent_module, "%.")) then
should_enable_module = false
logger.error(
('Doom module "%s.%s" depends on a module that is not enabled "%s.%s". Please enable the %s module.'):format(
section_name,
module_name,
dep_section_name,
dep_module_name,
dep_module_name
('Doom module "%s" depends on a module that is not enabled "%s". Please enable the %s module.'):format(
path_module,
dependent_module,
dependent_module
)
)
end
Expand All @@ -88,8 +87,9 @@ modules.load_modules = function()
spec.commit = utils.pick_compatible_field(spec.commit)
end

-- Only pin dependencies if doom.freeze_dependencies is true
spec.lock = spec.commit and doom.freeze_dependencies
if not doom.freeze_dependencies then
spec.commit = nil
end

-- Save module spec to be initialised later
table.insert(doom.packages, spec)
Expand Down Expand Up @@ -117,9 +117,11 @@ modules.load_modules = function()
)
end
end

profiler.stop(profile_msg)
end
end
end, { debug = doom.logging == "trace" or doom.logging == "debug" })

end

--- Applies user's commands, autocommands, packages from `use_*` helper functions.
Expand Down
14 changes: 10 additions & 4 deletions lua/doom/modules/core/nest/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,18 @@ mapper.configs["nvim-mapper"] = function()

local profiler = require("doom.services.profiler")
local count = 0
for section_name, _ in pairs(doom.modules) do
for module_name, module in pairs(doom[section_name]) do
require("doom.utils.modules").traverse_loaded(doom.modules, function(node, stack)
if node.type then
local module = node
local t_path = vim.tbl_map(function(stack_node)
return type(stack_node.key) == "string" and stack_node.key
end, stack)
local path_module = table.concat(t_path, ".")
if module.binds then
count = count + 1
vim.defer_fn(function()
-- table.insert(all_keymaps, type(module.binds) == "function" and module.binds() or module.binds)
local profiler_msg = ("keymaps(async)|module: %s.%s"):format(section_name, module_name)
local profiler_msg = ("keymaps(async)|module: %s"):format(path_module)
profiler.start(profiler_msg)
keymaps_service.applyKeymaps(
type(module.binds) == "function" and module.binds() or module.binds,
Expand All @@ -154,7 +159,8 @@ mapper.configs["nvim-mapper"] = function()
end, count)
end
end
end
end)

end

return mapper
26 changes: 16 additions & 10 deletions lua/doom/modules/features/whichkey/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,24 @@ whichkey.configs["which-key.nvim"] = function()

local keymaps_service = require("doom.services.keymaps")
local whichkey_integration = get_whichkey_integration()
for section_name, _ in pairs(doom.modules) do
for _, module in pairs(doom[section_name]) do
if module and module.binds then
-- table.insert(all_keymaps, type(module.binds) == "function" and module.binds() or module.binds)
keymaps_service.applyKeymaps(
type(module.binds) == "function" and module.binds() or module.binds,
nil,
{ whichkey_integration }
)

require("doom.utils.modules").traverse_loaded(
doom.modules,
function(node, stack)
if node.type then
local module = node
if module.binds then
keymaps_service.applyKeymaps(
type(module.binds) == "function" and module.binds() or module.binds,
nil,
{ whichkey_integration }
)
end
end
end
end
--, { debug = doom.settings.logging == "trace" or doom.settings.logging == "debug" }
)


-- Add user keymaps to whichkey user keymaps
if doom.binds and #doom.binds >= 1 then
Expand Down
75 changes: 75 additions & 0 deletions lua/doom/services/traverser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
--
-- TRAVERSER
--

-- TODO: More documentation

-- Default debugger print
local default_debug_node = function(node, stack)
local parent = stack[#stack]
local indent_str = string.rep("--", #stack)
local indent_cap = type(node) == "table" and "+" or ">"
print(
("default: %s%s %s"):format(
indent_str,
indent_cap,
type(node) == "table" and parent.key or node
)
)
end

-- Default debug levels
local default_log_levels =
{ debug = doom.logging == "trace" or doom.logging == "debug" }

local tree_traverser = {
build = function(builder_opts)
local traverser = builder_opts.traverser
local debug_node = builder_opts.debug_node or default_debug_node
local stack = {}
local result = {}

-- Traverse out, pops from stack, adds to result
local traverse_out = function()
table.remove(stack, #stack)
end

-- Error does not add to result or anything
local err = function(message)
table.remove(stack, #stack)
local path = vim.tbl_map(function(stack_node)
return "[" .. vim.inspect(stack_node.key) .. "]"
end, stack)
print(("%s\n Occursed at key `%s`."):format(message, table.concat(path, "")))
table.remove(result, #result)
end

local traverse_in
traverse_in = function(key, node)
table.insert(stack, { key = key, node = node })
table.insert(result, { node = node, stack = vim.deepcopy(stack) })
traverser(node, stack, traverse_in, traverse_out, err)
end

return function(tree, handler, opts)
result = {} -- Reset result
if opts == nil then
opts = default_log_levels
end

traverser(tree, stack, traverse_in, traverse_out, err)

if opts.debug and debug_node then
for _, value in ipairs(result) do
debug_node(value.node, value.stack)
end
end

for _, value in ipairs(result) do
handler(value.node, value.stack)
end
end
end,
}

return tree_traverser
52 changes: 51 additions & 1 deletion lua/doom/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,23 @@ utils.get_diagnostic_count = function(bufnr, severity)
end

--- Check if the given plugin is disabled in doom-nvim/modules.lua
---
--- You only need to supply one single arg if `section == <path-to-module>`.
---
--- @param section string The module section, e.g. features
--- @param plugin string The module identifier, e.g. statusline
--- @return boolean
utils.is_module_enabled = function(section, plugin)
local modules = require("doom.core.modules").enabled_modules

return modules[section] and vim.tbl_contains(modules[section], plugin)
if type(section) == "table" then
local tp = section
local name = table.remove(tp, #tp)
local subsec = utils.get_set_table_path(modules, tp)
return vim.tbl_contains(subsec, name)
else
return modules[section] and vim.tbl_contains(modules[section], plugin)
end
end

--- Rounds a number, optionally to the nearest decimal place
Expand Down Expand Up @@ -231,5 +241,45 @@ utils.left_pad = function(str, length, char)
return res, res ~= str
end

-- Get or Set a table path list.
--
-- Used with recursive module structures so that you can check if eg. a deep
-- path exists or if you want to create/set data to a deep path.
--
-- if no data supplies -> returns table path node or false if not exists
--
---@param head table The table to which you want target
---@param tp table Path that you wish to check in head
---@param data any If supplied, attaches this data to tp tip, eg. `{"a", "b"} -> b = data`
utils.get_set_table_path = function(head, tp, data)
if not head or not tp then
return false
end
local last = #tp
for i, p in ipairs(tp) do
if i ~= last then
if head[p] == nil then
if not data then
-- if a nil occurs, this means the path does no exist >> return
return false
end
head[p] = {}
end
head = head[p]
else
if data then
if type(data) == "function" then
data(head[p])
else
head[p] = data
end
else
-- print(vim.inspect(head), p)
return head[p]
end
end
end
end


return utils
Loading