diff --git a/lua/init.lua b/lua/init.lua new file mode 100644 index 0000000..210c4dc --- /dev/null +++ b/lua/init.lua @@ -0,0 +1,451 @@ +local word = require("word") +local log, mod, util = word.log, word.mod, word.utils + +local M = mod.create("cmd") + +M.maps = function() + Map.nmap(",wml", "Word mod list") + Map.nmap(",wmL", "Word mod load") +end +M.setup = function() + return { loaded = true, requires = {} } +end +M.data = { + data = { + + --- Handles the calling of the appropriate function based on the command the user entered + word_callback = function(data) + local args = data.fargs + + local current_buf = vim.api.nvim_get_current_buf() + local is_word = vim.bo[current_buf].filetype == "markdown" + + local function check_condition(condition) + if condition == nil then + return true + end + + if condition == "markdown" and not is_word then + return false + end + + if type(condition) == "function" then + return condition(current_buf, is_word) + end + + return condition + end + + local ref = { + subcommands = M.data.commands, + } + local argument_index = 0 + + for i, cmd in ipairs(args) do + if not ref.subcommands or vim.tbl_isempty(ref.subcommands) then + break + end + + ref = ref.subcommands[cmd] + + if not ref then + log.error( + ("Error when executing `:Word %s` - such a command does not exist!"):format( + table.concat(vim.list_slice(args, 1, i), " ") + ) + ) + return + elseif not check_condition(ref.condition) then + log.error( + ("Error when executing `:Word %s` - the command is currently disabled. Some commands will only become available under certain conditions, e.g. being within a `.Word` file!"):format( + table.concat(vim.list_slice(args, 1, i), " ") + ) + ) + return + end + + argument_index = i + end + + local argument_count = (#args - argument_index) + + if ref.args then + ref.min_args = ref.args + ref.max_args = ref.args + elseif ref.min_args and not ref.max_args then + ref.max_args = math.huge + else + ref.min_args = ref.min_args or 0 + ref.max_args = ref.max_args or 0 + end + + if #args == 0 or argument_count < ref.min_args then + local completions = M.data.data.generate_completions( + _, + table.concat({ "Word ", data.args, " " }) + ) + M.data.data.select_next_cmd_arg(data.args, completions) + return + elseif argument_count > ref.max_args then + log.error( + ("Error when executing `:Word %s` - too many arguments supplied! The command expects %s argument%s."):format( + data.args, + ref.max_args == 0 and "no" or ref.max_args, + ref.max_args == 1 and "" or "s" + ) + ) + return + end + + if not ref.name then + log.error( + ("Error when executing `:Word %s` - the ending command didn't have a `name` variable associated with it! This is an implementation error on the developer's side, so file a report to the author of the mod."):format( + data.args + ) + ) + return + end + + if not M.events.defined[ref.name] then + M.events.defined[ref.name] = mod.define_event(M, ref.name) + end + + mod.broadcast( + assert( + mod.create_event( + M, + table.concat({ "cmd.events.", ref.name }), + vim.list_slice(args, argument_index + 1) + ) + ) + ) + end, + + --- This function returns all available commands to be used for the :Word command + ---@param _ nil #Placeholder variable + ---@param command string #Supplied by nvim itself; the full typed out command + generate_completions = function(_, command) + local current_buf = vim.api.nvim_get_current_buf() + local is_word = vim.api.nvim_buf_get_option(current_buf, "filetype") + == "markdown" + + local function check_condition(condition) + if condition == nil then + return true + end + + if condition == "markdown" and not is_word then + return false + end + + if type(condition) == "function" then + return condition(current_buf, is_word) + end + + return condition + end + + command = command:gsub("^%s*", "") + + local splitcmd = vim.list_slice( + vim.split(command, " ", { + plain = true, + trimempty = true, + }), + 2 + ) + + local ref = { + subcommands = M.data.commands, + } + local last_valid_ref = ref + local last_completion_level = 0 + + for _, cmd in ipairs(splitcmd) do + if not ref or not check_condition(ref.condition) then + break + end + + ref = ref.subcommands or {} + ref = ref[cmd] + + if ref then + last_valid_ref = ref + last_completion_level = last_completion_level + 1 + end + end + + if not last_valid_ref.subcommands and last_valid_ref.complete then + if type(last_valid_ref.complete) == "function" then + last_valid_ref.complete = + last_valid_ref.complete(current_buf, is_word) + end + + if vim.endswith(command, " ") then + local completions = last_valid_ref.complete[#splitcmd - last_completion_level + 1] + or {} + + if type(completions) == "function" then + completions = completions(current_buf, is_word) or {} + end + + return completions + else + local completions = last_valid_ref.complete[#splitcmd - last_completion_level] + or {} + + if type(completions) == "function" then + completions = completions(current_buf, is_word) or {} + end + + return vim.tbl_filter(function(key) + return key:find(splitcmd[#splitcmd]) + end, completions) + end + end + + -- TODO: Fix `:Word m ` giving invalid completions + local keys = ref and vim.tbl_keys(ref.subcommands or {}) + or ( + vim.tbl_filter(function(key) + return key:find(splitcmd[#splitcmd]) + end, vim.tbl_keys(last_valid_ref.subcommands or {})) + ) + table.sort(keys) + + do + local subcommands = ( + ref and ref.subcommands or last_valid_ref.subcommands + ) or {} + + return vim.tbl_filter(function(key) + return check_condition(subcommands[key].condition) + end, keys) + end + end, + + --- Queries the user to select next argument + ---@param qargs table #A string of arguments previously supplied to the word command + ---@param choices table #all possible choices for the next argument + select_next_cmd_arg = function(qargs, choices) + local current = table.concat({ "Word ", qargs }) + + local query + + if vim.tbl_isempty(choices) then + query = function(...) + vim.ui.input(...) + end + else + query = function(...) + vim.ui.select(choices, ...) + end + end + + query({ + prompt = current, + }, function(choice) + if choice ~= nil then + vim.cmd(string.format("%s %s", current, choice)) + end + end) + end, + }, + commands = { + mod = { + subcommands = { + new = { + args = 1, + name = "mod.new", + }, + load = { + args = 1, + name = "mod.load", + }, + + list = { + args = 0, + name = "mod.list", + }, + }, + }, + }, + + -- The table containing all the functions. This can get a tad complex so I recommend you read the wiki entry + + ---@param mod_name string #An absolute path to a loaded init with a mod.config.commands table following a valid structure + add_commands = function(mod_name) + local mod_config = mod.get_mod(mod_name) + + if not mod_config or not mod_config.commands then + return + end + + M.data.commands = + vim.tbl_extend("force", M.data.commands, mod_config.commands) + end, + + -- add = function(cmd, cb) + -- mod.await("cmd", function(c) + -- c.add_commands_from_table({ + -- [cmd] = { + -- name = cmd, + -- callback = cb, + -- } + -- }) + -- end) + -- M.data.add_commands(cmd) + -- end, + + --- Recursively merges the provided table with the mod.config.commands table. + ---@param functions table #A table that follows the mod.config.commands structure + add_commands_from_table = function(functions) + M.data.commands = vim.tbl_extend("force", M.data.commands, functions) + end, + + --- Takes a relative path (e.g "list.mod") and loads it from the commands/ directory + ---@param name string #The relative path of the init we want to load + add_commands_from_file = function(name) + -- Attempt to require the file + local err, ret = pcall(require, "word.mod.cmd." .. name .. "init") + + -- If we've failed bail out + if not err then + log.warn( + "Could not load command" + .. name + .. "for init base.cmd - the corresponding mod.lua file does not exist." + ) + return + end + + -- Load the init from table + mod.load_mod_from_table(ret) + end, + + --- Rereads data from all mod and rebuild the list of available autocompletiinitinitons and commands + sync = function() + -- Loop through every loaded init and set up all their commands + for _, lm in pairs(mod.loaded_mod) do + if lm.data.commands then + M.data.add_commands_from_table(lm.data.commands) + end + end + end, + + --- Defines a custom completion function to use for `base.cmd`. + ---@param callback function The same function format as you would receive by being called by `:command -completion=customlist,v:lua.callback word`. + set_completion_callback = function(callback) + M.data.data.generate_completions = callback + end, +} +M.load = function() + -- Define the :word command with autocompletion taking any number of arguments (-nargs=*) + -- If the user passes no arguments or too few, we'll query them for the remainder using select_next_cmd_arg. + vim.api.nvim_create_user_command("Word", M.data.data.word_callback, { + desc = "The word command", + range = 2, + force = true, + -- bang = true, + nargs = "*", + complete = M.data.data.generate_completions, + }) + + -- Loop through all the command mod we want to load and load them + for _, command in ipairs(M.config.public.load) do + if command == "default" then + for _, base_command in ipairs(M.config.public.base) do + M.data.add_commands_from_file(base_command) + end + end + end +end + +M.config.public = { + -- A list of cmd mod to load automatically. + -- This feature will soon be deprecated, so it is not recommended to touch it. + load = { + "default", + }, + + -- A list of base commands to load. + -- + -- This feature will soon be deprecated, so it is not recommended to touch it. + base = { + "mod", + "back", + "rename", + }, +} +---@class cmd + +M.post_load = M.data.sync + +M.on_event = function(event) + if event.type == "cmd.events.mod.setup" then + local ok = pcall(mod.load_mod, event.content[1]) + + if not ok then + vim.notify( + string.format("init `%s` does not exist!", event.content[1]), + vim.log.levels.ERROR, + {} + ) + end + end + + if event.type == "cmd.events.mod.unload" then + end + + if event.type == "cmd.events.mod.list" then + local Popup = require("nui.popup") + + local mod_list_popup = Popup({ + position = "50%", + size = { width = "50%", height = "80%" }, + enter = true, + buf_options = { + filetype = "markdown", + modifiable = true, + readonly = false, + }, + win_options = { + conceallevel = 3, + concealcursor = "nvi", + }, + }) + + mod_list_popup:on("VimResized", function() + mod_list_popup:update_layout() + end) + + local function close() + mod_list_popup:unmount() + end + + mod_list_popup:map("n", "", close, {}) + mod_list_popup:map("n", "q", close, {}) + + local lines = {} + + for name, _ in pairs(word.mod.loaded_mod) do + table.insert(lines, "- `" .. name .. "`") + end + + vim.api.nvim_buf_set_lines(mod_list_popup.bufnr, 0, -1, true, lines) + + vim.bo[mod_list_popup.bufnr].modifiable = false + + mod_list_popup:mount() + end +end +M.events.subscribed = { + cmd = { + -- ["mod.new"] = true, + ["mod.unload"] = true, + ["mod.load"] = true, + ["mod.list"] = true, + }, +} + +return M diff --git a/lua/word/mod/config/init.lua b/lua/word/mod/config.lua similarity index 69% rename from lua/word/mod/config/init.lua rename to lua/word/mod/config.lua index 706eacf..8f28725 100644 --- a/lua/word/mod/config/init.lua +++ b/lua/word/mod/config.lua @@ -1,5 +1,5 @@ -local M = require("word.mod").create_meta( - ---@type string: name of config created +local M = require("word.mod").modules( +---@type string: name of config created "config", ---@brief rest of modules are loaded "ui", diff --git a/lua/word/mod/init.lua b/lua/word/mod/init.lua index 8676b55..965216e 100644 --- a/lua/word/mod/init.lua +++ b/lua/word/mod/init.lua @@ -20,7 +20,7 @@ Mod = setmetatable({}, { end, }) -Mod.default_mod = function(name) +Mod.default = function(name) return { setup = function() ---@type word.mod.Setup @@ -72,7 +72,7 @@ Mod.default_mod = function(name) events = { subscribed = { -- The events that the init is subscribed to }, - defined = { -- The events that the init itself has defined + defined = { -- The events that the init itself has defined }, }, required = {}, @@ -86,36 +86,36 @@ end --- @return word.Mod function Mod.create(name, imports) ---@type word.Mod - local new_mod = Mod.default_mod(name) + local new = Mod.default(name) if imports then for _, imp in ipairs(imports) do local fullpath = table.concat({ name, imp }, ".") if not Mod.load_mod(fullpath) then log.error( "Unable to load import '" - .. fullpath - .. "'! An error (see traceback below):" + .. fullpath + .. "'! An error (see traceback below):" ) assert(false) end - new_mod.import[fullpath] = Mod.loaded_mod[fullpath] + new.import[fullpath] = Mod.loaded_mod[fullpath] end end if name then - new_mod.name = name - new_mod.path = "mod." .. name - new_mod.namespace = "word.mod." .. name - vim.api.nvim_create_namespace(new_mod.namespace) + new.name = name + new.path = "mod." .. name + new.namespace = "word.mod." .. name + vim.api.nvim_create_namespace(new.namespace) end - return new_mod + return new end ---- Constructs a metainit from a list of submod. Modetamod are mod that can autoload batches of mod at once. +--- Constructs a default array of modules --- @param name string The name of the new metainit. Modake sure this is unique. The recommended naming convention is `category.modn` or `category.subcategory.modn`. --- @param ... string A list of init names to load. --- @return word.Mod -Mod.create_meta = function(name, ...) +Mod.modules = function(name, ...) ---@type word.Mod local m = Mod.create(name) @@ -186,20 +186,20 @@ function Mod.load_mod_from_table(m) -- Invoke the setup function. This function returns whether or not the loading of the init was successful and some metadata. ---@type word.mod.Setup local mod_load = m.setup and m.setup() - or { - loaded = true, - replaces = {}, - merge = false, - requires = {}, - wants = {}, - } + or { + loaded = true, + replaces = {}, + merge = false, + requires = {}, + wants = {}, + } -- We do not expect init.setup() to ever return nil, that's why this check is in place if not mod_load then log.error( "init" - .. m.name - .. "does not handle init loading correctly; init.setup() returned nil. Omitting..." + .. m.name + .. "does not handle init loading correctly; init.setup() returned nil. Omitting..." ) return false end @@ -231,15 +231,15 @@ function Mod.load_mod_from_table(m) if config.user.mod[req_mod] then log.trace( "Wanted init" - .. req_mod - .. "isn't loaded but can be as it's defined in the user's config. Loading..." + .. req_mod + .. "isn't loaded but can be as it's defined in the user's config. Loading..." ) if not Mod.load_mod(req_mod) then require("word.util.log").error( "Unable to load wanted init for" - .. m.name - .. "- the init didn't load successfully" + .. m.name + .. "- the init didn't load successfully" ) -- Modake sure to clean up after ourselves if the init failed to load @@ -248,7 +248,8 @@ function Mod.load_mod_from_table(m) end else log.error( - ("Unable to load init %s, wanted dependency %s was not satisfied. Be sure to load the init and its appropriate config too!"):format( + ("Unable to load init %s, wanted dependency %s was not satisfied. Be sure to load the init and its appropriate config too!") + :format( m.name, req_mod ) @@ -307,7 +308,8 @@ function Mod.load_mod_from_table(m) -- If this flag has already been set before, then throw an error - there is no way for us to know which hotswapped init should take priority. if mod_to_replace.replaced then log.error( - ("Unable to replace init %s - init replacement clashing detected. This error triggers when a init tries to be replaced more than two times - word doesn't know which replacement to prioritize."):format( + ("Unable to replace init %s - init replacement clashing detected. This error triggers when a init tries to be replaced more than two times - word doesn't know which replacement to prioritize.") + :format( mod_to_replace.name ) ) @@ -386,8 +388,8 @@ function Mod.load_mod(modn, cfg) if not modl then log.error( "Unable to load init" - .. modn - .. "- loaded file returned nil. Be sure to return the table created by mod.create() at the end of your init.lua file!" + .. modn + .. "- loaded file returned nil. Be sure to return the table created by mod.create() at the end of your init.lua file!" ) return false end @@ -395,8 +397,9 @@ function Mod.load_mod(modn, cfg) if modl == true then log.error( "An error has occurred when loading" - .. modn - .. "- loaded file didn't return anything meaningful. Be sure to return the table created by mod.create() at the end of your init.lua file!" + .. modn + .. + "- loaded file didn't return anything meaningful. Be sure to return the table created by mod.create() at the end of your init.lua file!" ) return false end @@ -409,8 +412,8 @@ function Mod.load_mod(modn, cfg) -- print(modl.config.custom, modl.config.public, config.mod[modn]) modl.config.custom = config.mod[modn] modl.config.public = - -- vim.tbl_extend("force", modl.config.public, modl.config.custom or {}) - utils.extend(modl.config.public, modl.config.custom or {}) + -- vim.tbl_extend("force", modl.config.public, modl.config.custom or {}) + utils.extend(modl.config.public, modl.config.custom or {}) end -- Pass execution onto load_mod_from_table() and let it handle the rest @@ -462,8 +465,8 @@ function Mod.get_mod_config(modn) if not Mod.is_mod_loaded(modn) then log.trace( "Attempt to get init config with name" - .. modn - .. "failed - init is not loaded." + .. modn + .. "failed - init is not loaded." ) return end @@ -486,8 +489,8 @@ function Mod.get_mod_version(modn) if not Mod.is_mod_loaded(modn) then log.trace( "Attempt to get init version with name" - .. modn - .. "failed - init is not loaded." + .. modn + .. "failed - init is not loaded." ) return end @@ -499,8 +502,8 @@ function Mod.get_mod_version(modn) if not version then log.trace( "Attempt to get init version with name" - .. modn - .. "failed - version variable not present." + .. modn + .. "failed - version variable not present." ) return end @@ -609,7 +612,7 @@ function Mod.create_event(m, type, content, ev) -- Retrieve the template from init.events.defined local event_template = - Mod.get_event_template(Mod.loaded_mod[modn] or { name = "" }, type) + Mod.get_event_template(Mod.loaded_mod[modn] or { name = "" }, type) if not event_template then log.warn("Unable to create event of type" .. type .. ". Returning nil...") @@ -635,7 +638,7 @@ function Mod.create_event(m, type, content, ev) new_event.cursor_position = vim.api.nvim_win_get_cursor(winid) local row_1b = new_event.cursor_position[1] new_event.line_content = - vim.api.nvim_buf_get_lines(bufid, row_1b - 1, row_1b, true)[1] + vim.api.nvim_buf_get_lines(bufid, row_1b - 1, row_1b, true)[1] new_event.referrer = m.name new_event.broadcast = true new_event.buffer = bufid @@ -653,8 +656,8 @@ function Mod.broadcast(event, callback) if not event.split_type then log.error( "Unable to broadcast event of type" - .. event.type - .. "- invalid event name" + .. event.type + .. "- invalid event name" ) return end diff --git a/lua/word/mod/note/init.lua b/lua/word/mod/note/init.lua index d0866e4..c7262a6 100644 --- a/lua/word/mod/note/init.lua +++ b/lua/word/mod/note/init.lua @@ -1,6 +1,6 @@ local word = require("word") local config, lib, log, mod = - require("word.config").config, word.lib, word.log, word.mod + require("word.config").config, word.lib, word.log, word.mod local M = mod.create("note") M.maps = function() @@ -36,13 +36,13 @@ M.data = { year_index = function() local yr = os.date("%Y") local ws = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local ws_path = M.required["workspace"].get_workspace(ws) local ix = M.config.public.note_folder - .. config.pathsep - .. yr - .. config.pathsep - .. "index.md" + .. config.pathsep + .. yr + .. config.pathsep + .. "index.md" local path = ws_path .. config.pathsep .. ix local index_exists = M.required["workspace"].file_exists(path) if index_exists then @@ -56,15 +56,15 @@ M.data = { local yr = os.date("%Y") local mo = os.date("%m") local ws = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local ws_path = M.required["workspace"].get_workspace(ws) local ix = M.config.public.note_folder - .. config.pathsep - .. yr - .. config.pathsep - .. mo - .. config.pathsep - .. "index.md" + .. config.pathsep + .. yr + .. config.pathsep + .. mo + .. config.pathsep + .. "index.md" local path = ws_path .. config.pathsep .. ix local index_exists = M.required["workspace"].file_exists(path) if index_exists then @@ -77,7 +77,7 @@ M.data = { select_month = function() end, note_index = function() local ws = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local ws_path = M.required["workspace"].get_workspace(ws) local ix = M.config.public.note_folder .. config.pathsep .. "index.md" local path = ws_path .. config.pathsep .. ix @@ -95,7 +95,7 @@ M.data = { open_year = function(time, custom_date) -- TODO(vhyrro): Change this to use word dates! local workspace = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local workspace_path = M.required["workspace"].get_workspace(workspace) local folder_name = M.config.public.note_folder local tmpl = M.config.public.template.year @@ -118,8 +118,8 @@ M.data = { local path = os.date( type(M.config.public.strategy) == "function" - and M.config.public.strategy(os.date("*t", time)) - or M.config.public.strategy, + and M.config.public.strategy(os.date("*t", time)) + or M.config.public.strategy, time ) @@ -135,20 +135,20 @@ M.data = { -- M.required["workspace"].create_file(folder_name..config.pathsep..path, workspace) if - not note_file_exists - and M.config.public.template.enable - and M.required["workspace"].file_exists( - workspace_path .. "/" .. folder_name .. "/" .. tmpl - ) + not note_file_exists + and M.config.public.template.enable + and M.required["workspace"].file_exists( + workspace_path .. "/" .. folder_name .. "/" .. tmpl + ) then vim.cmd( "$read " - .. workspace_path - .. "/" - .. folder_name - .. "/" - .. tmpl - .. "| silent! w" + .. workspace_path + .. "/" + .. folder_name + .. "/" + .. tmpl + .. "| silent! w" ) end end, @@ -156,7 +156,7 @@ M.data = { ---@param custom_date? string #A YYYY-mm-dd string that specifies a date to open the note at instead open_month = function(time, custom_date) local workspace = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local workspace_path = M.required["workspace"].get_workspace(workspace) local folder_name = M.config.public.note_folder local tmpl = M.config.public.template.month @@ -178,8 +178,8 @@ M.data = { local path = os.date( type(M.config.public.strategy) == "function" - and M.config.public.strategy(os.date("*t", time)) - or M.config.public.strategy, + and M.config.public.strategy(os.date("*t", time)) + or M.config.public.strategy, time ) @@ -195,20 +195,20 @@ M.data = { -- M.required["workspace"].create_file(folder_name..config.pathsep..path, workspace) if - not note_file_exists - and M.config.public.template.enable - and M.required["workspace"].file_exists( - workspace_path .. "/" .. folder_name .. "/" .. tmpl - ) + not note_file_exists + and M.config.public.template.enable + and M.required["workspace"].file_exists( + workspace_path .. "/" .. folder_name .. "/" .. tmpl + ) then vim.cmd( "$read " - .. workspace_path - .. "/" - .. folder_name - .. "/" - .. tmpl - .. "| silent! w" + .. workspace_path + .. "/" + .. folder_name + .. "/" + .. tmpl + .. "| silent! w" ) end end, @@ -227,7 +227,7 @@ M.data = { open_note = function(time, custom_date) -- TODO(vhyrro): Change this to use word dates! local workspace = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local workspace_path = M.required["workspace"].get_workspace(workspace) local folder_name = M.config.public.note_folder local tmpl = M.config.public.template.day @@ -249,8 +249,8 @@ M.data = { local path = os.date( type(M.config.public.strategy) == "function" - and M.config.public.strategy(os.date("*t", time)) - or M.config.public.strategy, + and M.config.public.strategy(os.date("*t", time)) + or M.config.public.strategy, time ) @@ -266,20 +266,20 @@ M.data = { -- M.required["workspace"].create_file(folder_name..config.pathsep..path, workspace) if - not note_file_exists - and M.config.public.template.enable - and M.required["workspace"].file_exists( - workspace_path .. "/" .. folder_name .. "/" .. tmpl - ) + not note_file_exists + and M.config.public.template.enable + and M.required["workspace"].file_exists( + workspace_path .. "/" .. folder_name .. "/" .. tmpl + ) then vim.cmd( "$read " - .. workspace_path - .. "/" - .. folder_name - .. "/" - .. tmpl - .. "| silent! w" + .. workspace_path + .. "/" + .. folder_name + .. "/" + .. tmpl + .. "| silent! w" ) end end, @@ -354,15 +354,15 @@ M.data = { --- Opens the toc file open_toc = function() local workspace = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local index = mod.get_mod_config("workspace").index local folder_name = M.config.public.note_folder -- If the toc exists, open it, if not, create it if - M.required["workspace"].file_exists( - folder_name .. config.pathsep .. index - ) + M.required["workspace"].file_exists( + folder_name .. config.pathsep .. index + ) then M.required["workspace"].open_file( workspace, @@ -376,7 +376,7 @@ M.data = { --- Creates or updates the toc file create_toc = function() local workspace = M.config.public.workspace - or M.required["workspace"].get_current_workspace()[1] + or M.required["workspace"].get_current_workspace()[1] local index = mod.get_mod_config("workspace").index local workspace_path = M.required["workspace"].get_workspace(workspace) local workspace_name_for_link = M.config.public.workspace or "" @@ -391,10 +391,10 @@ M.data = { path = path or "" local handle = vim.loop.fs_scandir( workspace_path - .. config.pathsep - .. folder_name - .. config.pathsep - .. path + .. config.pathsep + .. folder_name + .. config.pathsep + .. path ) if type(handle) ~= "userdata" then @@ -416,10 +416,10 @@ M.data = { local get_title = function(file) local buffer = vim.fn.bufadd( workspace_path - .. config.pathsep - .. folder_name - .. config.pathsep - .. file + .. config.pathsep + .. folder_name + .. config.pathsep + .. file ) local meta = M.required["workspace"].get_document_metadata(buffer) return meta.title @@ -459,7 +459,7 @@ M.data = { if mtype == "directory" then local months_handle = - get_fs_handle(name .. config.pathsep .. mname) + get_fs_handle(name .. config.pathsep .. mname) while true do -- dname is the day local dname, dtype = vim.loop.fs_scandir_next(months_handle) @@ -477,10 +477,10 @@ M.data = { -- Get the title from the metadata, else, it just base to the name of the file local title = get_title( name - .. config.pathsep - .. mname - .. config.pathsep - .. dname + .. config.pathsep + .. mname + .. config.pathsep + .. dname ) or file[1] -- Insert a new entry @@ -489,16 +489,16 @@ M.data = { tonumber(mname), tonumber(file[1]), "{:$" - .. workspace_name_for_link - .. config.pathsep - .. M.config.public.note_folder - .. config.pathsep - .. name - .. config.pathsep - .. mname - .. config.pathsep - .. file[1] - .. ":}", + .. workspace_name_for_link + .. config.pathsep + .. M.config.public.note_folder + .. config.pathsep + .. name + .. config.pathsep + .. mname + .. config.pathsep + .. file[1] + .. ":}", title, }) end) @@ -532,12 +532,12 @@ M.data = { parts[2], parts[3], "{:$" - .. workspace_name_for_link - .. config.pathsep - .. M.config.public.note_folder - .. config.pathsep - .. file[1] - .. ":}", + .. workspace_name_for_link + .. config.pathsep + .. M.config.public.note_folder + .. config.pathsep + .. file[1] + .. ":}", title, }) end) @@ -547,34 +547,34 @@ M.data = { vim.schedule(function() -- Gets a base format for the entries local format = M.config.public.toc_format - or function(entries) - local months_text = M.months - -- Convert the entries into a certain format to be written - local output = {} - local current_year - local current_month - for _, entry in ipairs(entries) do - -- Don't print the year and month if they haven't changed - if not current_year or current_year < entry[1] then - current_year = entry[1] - current_month = nil - table.insert(output, "* " .. current_year) - end - if not current_month or current_month < entry[2] then - current_month = entry[2] - table.insert(output, "** " .. months_text[current_month]) + or function(entries) + local months_text = M.months + -- Convert the entries into a certain format to be written + local output = {} + local current_year + local current_month + for _, entry in ipairs(entries) do + -- Don't print the year and month if they haven't changed + if not current_year or current_year < entry[1] then + current_year = entry[1] + current_month = nil + table.insert(output, "* " .. current_year) + end + if not current_month or current_month < entry[2] then + current_month = entry[2] + table.insert(output, "** " .. months_text[current_month]) + end + + -- Prints the file link + table.insert( + output, + " " .. entry[4] .. string.format("[%s]", entry[5]) + ) end - -- Prints the file link - table.insert( - output, - " " .. entry[4] .. string.format("[%s]", entry[5]) - ) + return output end - return output - end - M.required["workspace"].create_file( folder_name .. config.pathsep .. index, workspace or M.required["workspace"].get_current_workspace()[1] @@ -630,106 +630,7 @@ M.config.public.strategies = { nested = "%Y" .. config.pathsep .. "%m" .. config.pathsep .. "%d.md", } -M.load = function() - if M.config.public.strategies[M.config.public.strategy] then - M.config.public.strategy = - M.config.public.strategies[M.config.public.strategy] - end - - mod.await("cmd", function(cmd) - cmd.add_commands_from_table({ - note = { - min_args = 1, - max_args = 2, - subcommands = { - index = { args = 0, name = "note.index" }, - month = { - max_args = 1, - name = "note.month", - subcommands = { - index = { args = 0, name = "note.month.index" }, - previous = { - args = 0, - name = "note.month.previous", - }, - next = { - args = 0, - name = "note.month.next", - }, - }, - }, - week = { - subcommands = { - index = { args = 0, name = "note.week.index" }, - previous = { - args = 0, - name = "note.week.previous", - }, - next = { - args = 0, - name = "note.week.next", - }, - }, - max_args = 1, - name = "note.week", - }, - year = { - max_args = 1, - name = "note.year", - subcommands = { - index = { args = 0, name = "note.year.index" }, - previous = { - args = 0, - name = "note.year.previous", - }, - next = { - args = 0, - name = "note.year.next", - }, - }, - }, - capture = { args = 0, name = "note.capture" }, - tomorrow = { args = 0, name = "note.tomorrow" }, - yesterday = { args = 0, name = "note.yesterday" }, - today = { args = 0, name = "note.today" }, - calendar = { max_args = 1, name = "note.calendar" }, -- format :yyyy-mm-dd - template = { - subcommands = { - year = { - name = "notes.template.year", - args = 0, - }, - week = { - name = "notes.template.week", - args = 0, - }, - month = { - name = "notes.template.month", - args = 0, - }, - day = { - name = "notes.template.day", - args = 0, - }, - }, - args = 0, - name = "note.template", - }, - toc = { - args = 1, - name = "note.toc", - subcommands = { - open = { args = 0, name = "note.toc.open" }, - update = { args = 0, name = "note.toc.update" }, - }, - }, - }, - }, - }) - end) -end - -M.on_event = function(event) +M.on = function(event) local ty = event.split_type[1] local ev = event.split_type[2] if ty == "cmd" then @@ -771,10 +672,10 @@ M.on_event = function(event) M.data.open_note( nil, string.format("%04d", osdate.year) - .. "-" - .. string.format("%02d", osdate.month) - .. "-" - .. string.format("%02d", osdate.day) + .. "-" + .. string.format("%02d", osdate.month) + .. "-" + .. string.format("%02d", osdate.day) ) end), }) @@ -855,6 +756,102 @@ M.data.timetable = { M.data.time = os.time() M.data.weekday = tonumber(os.date("%w", os.time(M.data.timetable))) M.setup = function() + if M.config.public.strategies[M.config.public.strategy] then + M.config.public.strategy = + M.config.public.strategies[M.config.public.strategy] + end + + mod.await("cmd", function(cmd) + cmd.add_commands_from_table({ + note = { + min_args = 1, + max_args = 2, + subcommands = { + index = { args = 0, name = "note.index" }, + month = { + max_args = 1, + name = "note.month", + subcommands = { + index = { args = 0, name = "note.month.index" }, + previous = { + args = 0, + name = "note.month.previous", + }, + next = { + args = 0, + name = "note.month.next", + }, + }, + }, + week = { + subcommands = { + index = { args = 0, name = "note.week.index" }, + previous = { + args = 0, + name = "note.week.previous", + }, + next = { + args = 0, + name = "note.week.next", + }, + }, + max_args = 1, + name = "note.week", + }, + year = { + max_args = 1, + name = "note.year", + subcommands = { + index = { args = 0, name = "note.year.index" }, + previous = { + args = 0, + name = "note.year.previous", + }, + next = { + args = 0, + name = "note.year.next", + }, + }, + }, + capture = { args = 0, name = "note.capture" }, + tomorrow = { args = 0, name = "note.tomorrow" }, + yesterday = { args = 0, name = "note.yesterday" }, + today = { args = 0, name = "note.today" }, + calendar = { max_args = 1, name = "note.calendar" }, -- format :yyyy-mm-dd + template = { + subcommands = { + year = { + name = "notes.template.year", + args = 0, + }, + week = { + name = "notes.template.week", + args = 0, + }, + month = { + name = "notes.template.month", + args = 0, + }, + day = { + name = "notes.template.day", + args = 0, + }, + }, + args = 0, + name = "note.template", + }, + toc = { + args = 1, + name = "note.toc", + subcommands = { + open = { args = 0, name = "note.toc.open" }, + update = { args = 0, name = "note.toc.update" }, + }, + }, + }, + }, + }) + end) return { loaded = true, requires = {