aboutsummaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authormoxie <moxie@3kgcat.fi>2026-03-14 10:28:08 +0200
committermoxie <moxie@3kgcat.fi>2026-03-14 10:29:54 +0200
commitc8dc1635f8a921269f714117f414bbc7ba24f9fd (patch)
tree336a0bb466a5e023c0a0e6472c9876ff7458de68 /lua
parentffc0482ab89924cb35155fa82033e3d0ddc6c93d (diff)
refactor: consolidate modules and improve structure
Diffstat (limited to 'lua')
-rw-r--r--lua/muwiki/config.lua9
-rw-r--r--lua/muwiki/external.lua (renamed from lua/muwiki/handlers.lua)17
-rw-r--r--lua/muwiki/files.lua98
-rw-r--r--lua/muwiki/fs.lua85
-rw-r--r--lua/muwiki/health.lua4
-rw-r--r--lua/muwiki/init.lua13
-rw-r--r--lua/muwiki/io.lua161
-rw-r--r--lua/muwiki/links.lua280
-rw-r--r--lua/muwiki/links/creation.lua65
-rw-r--r--lua/muwiki/links/detection.lua58
-rw-r--r--lua/muwiki/links/navigation.lua20
-rw-r--r--lua/muwiki/links/open.lua94
-rw-r--r--lua/muwiki/links/url_handlers.lua71
-rw-r--r--lua/muwiki/paths.lua35
-rw-r--r--lua/muwiki/template.lua (renamed from lua/muwiki/templates.lua)4
15 files changed, 478 insertions, 536 deletions
diff --git a/lua/muwiki/config.lua b/lua/muwiki/config.lua
index 2a89427..1e7e3de 100644
--- a/lua/muwiki/config.lua
+++ b/lua/muwiki/config.lua
@@ -1,5 +1,3 @@
-local fs = require('muwiki.fs')
-
local M = {}
M.options = {
@@ -23,6 +21,11 @@ date: ${date}
create_missing_dirs = false,
}
+local function dir_exists(path)
+ local stat = vim.uv.fs_stat(path)
+ return stat and stat.type == 'directory'
+end
+
function M.setup(opts)
opts = opts or {}
@@ -46,7 +49,7 @@ function M.setup(opts)
end
for _, dir in ipairs(M.options.dirs or {}) do
- if not fs.dir_exists(dir.path) then
+ if not dir_exists(dir.path) then
vim.notify('Wiki directory not found: ' .. dir.path, vim.log.levels.WARN)
end
end
diff --git a/lua/muwiki/handlers.lua b/lua/muwiki/external.lua
index 4b320c3..cf26aca 100644
--- a/lua/muwiki/handlers.lua
+++ b/lua/muwiki/external.lua
@@ -1,8 +1,23 @@
local config = require('muwiki.config')
-
+local paths = require('muwiki.paths')
local M = {}
+function M.open(url)
+ if type(url) ~= 'string' then
+ vim.notify('Invalid URL type', vim.log.levels.ERROR)
+ return false
+ end
+
+ local valid, err = paths.validate_url_scheme(url)
+ if not valid then
+ vim.notify(err, vim.log.levels.ERROR)
+ return false
+ end
+
+ vim.system({ 'xdg-open', url }, { detach = true })
+ return true
+end
function M.execute(handler, url)
if type(handler.cmd) == 'function' then
diff --git a/lua/muwiki/files.lua b/lua/muwiki/files.lua
deleted file mode 100644
index 6ec2bc2..0000000
--- a/lua/muwiki/files.lua
+++ /dev/null
@@ -1,98 +0,0 @@
-local config = require('muwiki.config')
-local paths = require('muwiki.paths')
-local fs = require('muwiki.fs')
-
-local M = {}
-
-function M.open_in_buffer(filepath)
- local bufnr = vim.fn.bufnr(filepath, true)
- vim.api.nvim_win_set_buf(0, bufnr)
-end
-
-function M.open_external(url)
- if type(url) ~= 'string' then
- vim.notify('Invalid URL type', vim.log.levels.ERROR)
- return false
- end
-
- local valid, err = paths.validate_url_scheme(url)
- if not valid then
- vim.notify(err, vim.log.levels.ERROR)
- return false
- end
-
- vim.system({ 'xdg-open', url }, { detach = true })
- return true
-end
-
-function M.open_index(name)
- local wiki_path = config.wiki_path(name)
- if not wiki_path then
- return
- end
-
- local index_path = vim.fs.joinpath(wiki_path, config.options.index_file)
- M.open_in_buffer(index_path)
-end
-
-function M.resolve(filepath, wiki_root)
- if not wiki_root then
- error('wiki_root parameter is required for secure path resolution')
- end
-
- local path = paths.strip_file_protocol(filepath)
-
- local resolved = paths.resolve(path, wiki_root)
-
- return paths.validate_within_wiki(resolved, wiki_root, filepath)
-end
-
-function M.is_text_file(ext)
- local ext_lower = ext:lower()
- for _, text_ext in ipairs(config.options.text_extensions) do
- if ext_lower == text_ext then
- return true
- end
- end
- return false
-end
-
-function M.normalize_filename(text)
- local normalized = text:lower()
- normalized = normalized:gsub('%s+', '_')
- normalized = normalized:gsub('[^%w_%-%.]', '')
- return normalized
-end
-
-function M.open_wiki_file(filepath)
- local templates = require('muwiki.templates')
-
- local exists = fs.file_exists(filepath)
-
- if not exists and config.options.create_missing_dirs then
- local wiki_root = config.wiki_root(0)
- if wiki_root then
- local mode = config.options.create_missing_dirs
-
- if mode == 'prompt' then
- fs.ensure_parent_dirs(filepath, wiki_root, mode, function(success)
- if success then
- M.open_in_buffer(filepath)
- templates.init_file(vim.api.nvim_get_current_buf(), filepath)
- end
- end)
- return
- else
- local success = fs.ensure_parent_dirs(filepath, wiki_root, mode)
- if not success then
- return
- end
- end
- end
- end
-
- M.open_in_buffer(filepath)
- templates.init_file(vim.api.nvim_get_current_buf(), filepath)
-end
-
-return M
diff --git a/lua/muwiki/fs.lua b/lua/muwiki/fs.lua
deleted file mode 100644
index 6d53c0a..0000000
--- a/lua/muwiki/fs.lua
+++ /dev/null
@@ -1,85 +0,0 @@
-local paths = require('muwiki.paths')
-
-local M = {}
-
-function M.file_exists(path)
- local stat = vim.uv.fs_stat(path)
- return stat and stat.type == 'file'
-end
-
-function M.dir_exists(path)
- local stat = vim.uv.fs_stat(path)
- return stat and stat.type == 'directory'
-end
-
-function M.create_dir_safely(dirpath, wiki_root)
- if not paths.is_within_wiki(dirpath, wiki_root) then
- return false, 'Directory is outside wiki root'
- end
-
- if M.dir_exists(dirpath) then
- return true, nil
- end
-
- if vim.fn.mkdir(dirpath, 'p') ~= 1 then
- return false, 'Failed to create directory'
- end
-
- if not paths.is_within_wiki(dirpath, wiki_root) then
- vim.fn.delete(dirpath, 'd')
- return false, 'Symlink attack detected'
- end
-
- return true, nil
-end
-
-function M.ensure_parent_dirs(filepath, wiki_root, mode, callback)
- local dirpath = vim.fs.dirname(filepath)
-
- if M.dir_exists(dirpath) then
- if callback then
- callback(true)
- end
- return true
- end
-
- local function do_create()
- local success, err = M.create_dir_safely(dirpath, wiki_root)
- if not success then
- vim.notify(string.format('Cannot create directory: %s', err), vim.log.levels.ERROR)
- if callback then
- callback(false)
- end
- return false
- end
-
- if mode == 'notify' then
- vim.notify(string.format('Created directory: %s', dirpath), vim.log.levels.INFO)
- end
-
- if callback then
- callback(true)
- end
- return true
- end
-
- if mode == 'prompt' then
- vim.ui.select({ 'Yes', 'No' }, {
- prompt = string.format('Directory does not exist. Create %s?', dirpath),
- }, function(choice)
- if choice == 'Yes' then
- do_create()
- else
- vim.notify('Directory creation cancelled', vim.log.levels.INFO)
- if callback then
- callback(false)
- end
- end
- end)
- return nil
- end
-
- return do_create()
-end
-
-return M
diff --git a/lua/muwiki/health.lua b/lua/muwiki/health.lua
index a118cc8..2dfd45b 100644
--- a/lua/muwiki/health.lua
+++ b/lua/muwiki/health.lua
@@ -1,5 +1,5 @@
-local fs = require('muwiki.fs')
+local io_module = require('muwiki.io')
local M = {}
@@ -26,7 +26,7 @@ M.check = function()
vim.health.info('Add to your config: dirs = {{name = "default", path = "~/wiki"}}')
else
for _, dir in ipairs(cfg.dirs) do
- if fs.dir_exists(dir.path) then
+ if io_module.dir_exists(dir.path) then
vim.health.ok(string.format("Wiki '%s': %s", dir.name, dir.path))
else
vim.health.warn(string.format("Wiki '%s': %s (not found)", dir.name, dir.path))
diff --git a/lua/muwiki/init.lua b/lua/muwiki/init.lua
index 0369692..5538d91 100644
--- a/lua/muwiki/init.lua
+++ b/lua/muwiki/init.lua
@@ -1,4 +1,3 @@
-
local M = {}
local config = require('muwiki.config')
@@ -8,27 +7,27 @@ M.setup = function(opts)
end
function M.open_link()
- require('muwiki.links.open').open_link()
+ require('muwiki.links').open_link()
end
function M.next_link()
- require('muwiki.links.navigation').next_link()
+ require('muwiki.links').next_link()
end
function M.prev_link()
- require('muwiki.links.navigation').prev_link()
+ require('muwiki.links').prev_link()
end
function M.open_link_with()
- require('muwiki.links.open').open_link_with()
+ require('muwiki.links').open_link_with()
end
function M.create_link()
- require('muwiki.links.creation').create_link()
+ require('muwiki.links').create_link()
end
function M.open_index(name)
- require('muwiki.files').open_index(name)
+ require('muwiki.io').open_index(name)
end
function M.wiki_root(bufnr)
diff --git a/lua/muwiki/io.lua b/lua/muwiki/io.lua
new file mode 100644
index 0000000..e86fb2e
--- /dev/null
+++ b/lua/muwiki/io.lua
@@ -0,0 +1,161 @@
+local config = require('muwiki.config')
+local paths = require('muwiki.paths')
+
+local M = {}
+
+function M.exists(path)
+ local stat = vim.uv.fs_stat(path)
+ return stat and stat.type or nil
+end
+
+function M.file_exists(path)
+ return M.exists(path) == 'file'
+end
+
+function M.dir_exists(path)
+ return M.exists(path) == 'directory'
+end
+
+function M.create_dir_safely(dirpath, wiki_root)
+ if not paths.is_within_wiki(dirpath, wiki_root) then
+ return false, 'Directory is outside wiki root'
+ end
+
+ if M.dir_exists(dirpath) then
+ return true, nil
+ end
+
+ if vim.fn.mkdir(dirpath, 'p') ~= 1 then
+ return false, 'Failed to create directory'
+ end
+
+ if not paths.is_within_wiki(dirpath, wiki_root) then
+ vim.fn.delete(dirpath, 'd')
+ return false, 'Symlink attack detected'
+ end
+
+ return true, nil
+end
+
+function M.ensure_parent_dirs(filepath, wiki_root, mode, callback)
+ local dirpath = vim.fs.dirname(filepath)
+
+ if M.dir_exists(dirpath) then
+ if callback then
+ callback(true)
+ end
+ return true
+ end
+
+ local function do_create()
+ local success, err = M.create_dir_safely(dirpath, wiki_root)
+ if not success then
+ vim.notify(string.format('Cannot create directory: %s', err), vim.log.levels.ERROR)
+ if callback then
+ callback(false)
+ end
+ return false
+ end
+
+ if mode == 'notify' then
+ vim.notify(string.format('Created directory: %s', dirpath), vim.log.levels.INFO)
+ end
+
+ if callback then
+ callback(true)
+ end
+ return true
+ end
+
+ if mode == 'prompt' then
+ vim.ui.select({ 'Yes', 'No' }, {
+ prompt = string.format('Directory does not exist. Create %s?', dirpath),
+ }, function(choice)
+ if choice == 'Yes' then
+ do_create()
+ else
+ vim.notify('Directory creation cancelled', vim.log.levels.INFO)
+ if callback then
+ callback(false)
+ end
+ end
+ end)
+ return nil
+ end
+
+ return do_create()
+end
+
+function M.open_in_buffer(filepath)
+ local bufnr = vim.fn.bufnr(filepath, true)
+ vim.api.nvim_win_set_buf(0, bufnr)
+end
+
+function M.open_index(name)
+ local wiki_path = config.wiki_path(name)
+ if not wiki_path then
+ return
+ end
+
+ local index_path = vim.fs.joinpath(wiki_path, config.options.index_file)
+ M.open_in_buffer(index_path)
+end
+
+function M.resolve(filepath, wiki_root)
+ if not wiki_root then
+ error('wiki_root parameter is required for secure path resolution')
+ end
+
+ local path = paths.strip_file_protocol(filepath)
+ local resolved = paths.resolve(path, wiki_root)
+ return paths.validate_within_wiki(resolved, wiki_root, filepath)
+end
+
+function M.is_text_file(ext)
+ local ext_lower = ext:lower()
+ for _, text_ext in ipairs(config.options.text_extensions) do
+ if ext_lower == text_ext then
+ return true
+ end
+ end
+ return false
+end
+
+function M.normalize_filename(text)
+ local normalized = text:lower()
+ normalized = normalized:gsub('%s+', '_')
+ normalized = normalized:gsub('[^%w_%-%.]', '')
+ return normalized
+end
+
+function M.open_wiki_file(filepath)
+ local template = require('muwiki.template')
+ local exists = M.file_exists(filepath)
+
+ if not exists and config.options.create_missing_dirs then
+ local wiki_root = config.wiki_root(0)
+ if wiki_root then
+ local mode = config.options.create_missing_dirs
+
+ if mode == 'prompt' then
+ M.ensure_parent_dirs(filepath, wiki_root, mode, function(success)
+ if success then
+ M.open_in_buffer(filepath)
+ template.init_file(vim.api.nvim_get_current_buf(), filepath)
+ end
+ end)
+ return
+ else
+ local success = M.ensure_parent_dirs(filepath, wiki_root, mode)
+ if not success then
+ return
+ end
+ end
+ end
+ end
+
+ M.open_in_buffer(filepath)
+ template.init_file(vim.api.nvim_get_current_buf(), filepath)
+end
+
+return M
diff --git a/lua/muwiki/links.lua b/lua/muwiki/links.lua
new file mode 100644
index 0000000..990ecb1
--- /dev/null
+++ b/lua/muwiki/links.lua
@@ -0,0 +1,280 @@
+local config = require('muwiki.config')
+local paths = require('muwiki.paths')
+local io_module = require('muwiki.io')
+local external = require('muwiki.external')
+
+local M = {}
+
+local function get_link_type(target)
+ if target:match('^https?://') then
+ return 'web'
+ end
+ if target:match('^file://') then
+ return 'file'
+ end
+ return 'wiki'
+end
+
+function M.get_link()
+ local cursor = vim.api.nvim_win_get_cursor(0)
+
+ local ok, node = pcall(vim.treesitter.get_node, {
+ bufnr = 0,
+ pos = { cursor[1] - 1, cursor[2] },
+ lang = 'markdown',
+ ignore_injections = false,
+ })
+
+ if not ok or not node then
+ return nil
+ end
+
+ local link_node = node ---@type TSNode|nil
+ while link_node and link_node:type() ~= 'inline_link' do
+ link_node = link_node:parent()
+ end
+
+ if not link_node then
+ return nil
+ end
+
+ local text_node, dest_node
+ for child in link_node:iter_children() do
+ local t = child:type()
+ if t == 'link_text' then
+ text_node = child
+ elseif t == 'link_destination' then
+ dest_node = child
+ end
+ end
+
+ if not text_node or not dest_node then
+ return nil
+ end
+
+ local destination = vim.treesitter.get_node_text(dest_node, 0)
+ return {
+ text = vim.treesitter.get_node_text(text_node, 0),
+ target = destination,
+ type = get_link_type(destination),
+ }
+end
+
+local function resolve_file_url(url)
+ local path = paths.strip_file_protocol(url)
+ local path_type = paths.get_path_type(path)
+
+ if path_type == 'relative' then
+ local current_dir = vim.fs.dirname(vim.api.nvim_buf_get_name(0))
+ path = vim.fs.joinpath(current_dir, path)
+ end
+
+ return 'file://' .. vim.fs.normalize(path)
+end
+
+function M.handle_web_link(url)
+ if not config.options.use_external_handlers then
+ return
+ end
+ external.open(url)
+end
+
+function M.handle_file_url(url)
+ if not config.options.use_external_handlers then
+ return
+ end
+ local absolute_url = resolve_file_url(url)
+ external.open(absolute_url)
+end
+
+function M.handle_file_link(target, wiki_root)
+ local ok, file_path = pcall(io_module.resolve, target, wiki_root)
+ if not ok then
+ vim.notify(string.format('Cannot resolve path: %s', target), vim.log.levels.ERROR)
+ return
+ end
+
+ if not io_module.file_exists(file_path) then
+ vim.notify(string.format('File not found: %s', file_path), vim.log.levels.ERROR)
+ return
+ end
+
+ local ext = file_path:match('%.([^%.]+)$') or ''
+ if not io_module.is_text_file(ext) then
+ if not config.options.use_external_handlers then
+ return
+ end
+ external.open(file_path)
+ return
+ end
+
+ io_module.open_in_buffer(file_path)
+end
+
+function M.handle_wiki_link(target, wiki_root)
+ local file_path = io_module.resolve(target, wiki_root)
+ io_module.open_wiki_file(file_path)
+end
+
+local function get_wiki_root_or_notify()
+ local wiki_root = config.wiki_root(0)
+ if not wiki_root then
+ vim.notify('Not in a wiki buffer', vim.log.levels.ERROR)
+ return nil
+ end
+ return wiki_root
+end
+
+function M.open_link()
+ local link = M.get_link()
+ if not link then
+ vim.notify('No link found under cursor', vim.log.levels.WARN)
+ return
+ end
+
+ if link.type == 'web' then
+ M.handle_web_link(link.target)
+ return
+ end
+
+ local wiki_root = get_wiki_root_or_notify()
+ if not wiki_root then
+ return
+ end
+
+ if link.type == 'file' then
+ if vim.startswith(link.target, 'file://') then
+ M.handle_file_url(link.target)
+ else
+ M.handle_file_link(link.target, wiki_root)
+ end
+ return
+ end
+
+ M.handle_wiki_link(link.target, wiki_root)
+end
+
+function M.open_link_with()
+ local link = M.get_link()
+ if not link then
+ vim.notify('No link found under cursor', vim.log.levels.WARN)
+ return
+ end
+
+ if link.type == 'wiki' then
+ vim.notify('Menu not available for wiki links', vim.log.levels.WARN)
+ return
+ end
+
+ local url = link.target
+ if link.type == 'file' then
+ local wiki_root = get_wiki_root_or_notify()
+ if not wiki_root then
+ return
+ end
+ url = io_module.resolve(url, wiki_root)
+ end
+
+ local matching_handlers = external.get_matching(url)
+
+ if #matching_handlers == 0 then
+ vim.notify('No handlers available for this URL', vim.log.levels.WARN)
+ return
+ end
+
+ if #matching_handlers == 1 then
+ external.execute(matching_handlers[1], url)
+ return
+ end
+
+ local handler_names = {}
+ for _, handler in ipairs(matching_handlers) do
+ table.insert(handler_names, handler.name)
+ end
+
+ vim.ui.select(handler_names, {
+ prompt = 'Open with:',
+ }, function(choice, idx)
+ if choice and idx then
+ external.execute(matching_handlers[idx], url)
+ end
+ end)
+end
+
+function M.create_link()
+ local mode = vim.fn.mode()
+ if mode ~= 'v' and mode ~= 'V' then
+ vim.notify('Must be in visual mode to create a link', vim.log.levels.WARN)
+ return
+ end
+
+ local start_pos = vim.fn.getpos('v')
+ local end_pos = vim.fn.getpos('.')
+ local region = vim.fn.getregion(start_pos, end_pos, { type = mode })
+
+ if not region or #region == 0 then
+ vim.notify('No text selected', vim.log.levels.WARN)
+ return
+ end
+
+ if #region > 1 then
+ vim.notify('Multi-line selection not supported', vim.log.levels.WARN)
+ return
+ end
+
+ local selected_text = region[1]
+ local normalized = io_module.normalize_filename(selected_text)
+ local link_target = normalized .. '.md'
+ local link_text = string.format('[%s](%s)', selected_text, link_target)
+
+ local start_row = start_pos[2]
+ local start_col = start_pos[3]
+ local end_row = end_pos[2]
+ local end_col = end_pos[3]
+
+ if start_row > end_row or (start_row == end_row and start_col > end_col) then
+ start_row, end_row = end_row, start_row
+ start_col, end_col = end_col, start_col
+ end
+
+ start_row = start_row - 1
+ start_col = start_col - 1
+ end_row = end_row - 1
+
+ if mode == 'V' then
+ start_col = 0
+ local line = vim.api.nvim_buf_get_lines(0, end_row, end_row + 1, false)[1]
+ end_col = #line
+ end
+
+ vim.api.nvim_buf_set_text(0, start_row, start_col, end_row, end_col, { link_text })
+ vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Esc>', true, false, true), 'n', false)
+
+ local wiki_root = config.wiki_root(0)
+ if not wiki_root then
+ vim.notify('Not in a wiki buffer', vim.log.levels.ERROR)
+ return
+ end
+
+ local target_path = io_module.resolve(link_target, wiki_root)
+ io_module.open_wiki_file(target_path)
+end
+
+local function jump_link(direction)
+ local flags = direction == 'next' and 'w' or 'bw'
+ local msg = direction == 'next' and 'No more links' or 'No previous links'
+
+ if vim.fn.search('\\[.\\{-}\\]', flags) == 0 then
+ vim.notify(msg, vim.log.levels.INFO)
+ end
+end
+
+function M.next_link()
+ jump_link('next')
+end
+
+function M.prev_link()
+ jump_link('prev')
+end
+
+return M
diff --git a/lua/muwiki/links/creation.lua b/lua/muwiki/links/creation.lua
deleted file mode 100644
index 81c45a6..0000000
--- a/lua/muwiki/links/creation.lua
+++ /dev/null
@@ -1,65 +0,0 @@
-local M = {}
-
-function M.create_link()
- local files = require('muwiki.files')
- local config = require('muwiki.config')
-
- local mode = vim.fn.mode()
- if mode ~= 'v' and mode ~= 'V' then
- vim.notify('Must be in visual mode to create a link', vim.log.levels.WARN)
- return
- end
-
- local start_pos = vim.fn.getpos('v')
- local end_pos = vim.fn.getpos('.')
- local region = vim.fn.getregion(start_pos, end_pos, { type = mode })
-
- if not region or #region == 0 then
- vim.notify('No text selected', vim.log.levels.WARN)
- return
- end
-
- if #region > 1 then
- vim.notify('Multi-line selection not supported', vim.log.levels.WARN)
- return
- end
-
- local selected_text = region[1]
- local normalized = files.normalize_filename(selected_text)
- local link_target = normalized .. '.md'
- local link_text = string.format('[%s](%s)', selected_text, link_target)
-
- local start_row = start_pos[2]
- local start_col = start_pos[3]
- local end_row = end_pos[2]
- local end_col = end_pos[3]
-
- if start_row > end_row or (start_row == end_row and start_col > end_col) then
- start_row, end_row = end_row, start_row
- start_col, end_col = end_col, start_col
- end
-
- start_row = start_row - 1
- start_col = start_col - 1
- end_row = end_row - 1
-
- if mode == 'V' then
- start_col = 0
- local line = vim.api.nvim_buf_get_lines(0, end_row, end_row + 1, false)[1]
- end_col = #line
- end
-
- vim.api.nvim_buf_set_text(0, start_row, start_col, end_row, end_col, { link_text })
- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Esc>', true, false, true), 'n', false)
-
- local wiki_root = config.wiki_root(0)
- if not wiki_root then
- vim.notify('Not in a wiki buffer', vim.log.levels.ERROR)
- return
- end
-
- local target_path = files.resolve(link_target, wiki_root)
- files.open_wiki_file(target_path)
-end
-
-return M
diff --git a/lua/muwiki/links/detection.lua b/lua/muwiki/links/detection.lua
deleted file mode 100644
index 7b1f317..0000000
--- a/lua/muwiki/links/detection.lua
+++ /dev/null
@@ -1,58 +0,0 @@
-local M = {}
-
-local function get_link_type(target)
- if target:match('^https?://') then
- return 'web'
- end
- if target:match('^file://') then
- return 'file'
- end
- return 'wiki'
-end
-
-function M.get_link()
- local cursor = vim.api.nvim_win_get_cursor(0)
-
- local ok, node = pcall(vim.treesitter.get_node, {
- bufnr = 0,
- pos = { cursor[1] - 1, cursor[2] },
- lang = 'markdown',
- ignore_injections = false,
- })
-
- if not ok or not node then
- return nil
- end
-
- local link_node = node ---@type TSNode|nil
- while link_node and link_node:type() ~= 'inline_link' do
- link_node = link_node:parent()
- end
-
- if not link_node then
- return nil
- end
-
- local text_node, dest_node
- for child in link_node:iter_children() do
- local t = child:type()
- if t == 'link_text' then
- text_node = child
- elseif t == 'link_destination' then
- dest_node = child
- end
- end
-
- if not text_node or not dest_node then
- return nil
- end
-
- local destination = vim.treesitter.get_node_text(dest_node, 0)
- return {
- text = vim.treesitter.get_node_text(text_node, 0),
- target = destination,
- type = get_link_type(destination),
- }
-end
-
-return M
diff --git a/lua/muwiki/links/navigation.lua b/lua/muwiki/links/navigation.lua
deleted file mode 100644
index 42b6654..0000000
--- a/lua/muwiki/links/navigation.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local M = {}
-
-local function jump_link(direction)
- local flags = direction == 'next' and 'w' or 'bw'
- local msg = direction == 'next' and 'No more links' or 'No previous links'
-
- if vim.fn.search('\\[.\\{-}\\]', flags) == 0 then
- vim.notify(msg, vim.log.levels.INFO)
- end
-end
-
-function M.next_link()
- jump_link('next')
-end
-
-function M.prev_link()
- jump_link('prev')
-end
-
-return M
diff --git a/lua/muwiki/links/open.lua b/lua/muwiki/links/open.lua
deleted file mode 100644
index c8a1233..0000000
--- a/lua/muwiki/links/open.lua
+++ /dev/null
@@ -1,94 +0,0 @@
-local config = require('muwiki.config')
-local links = require('muwiki.links.detection')
-local files = require('muwiki.files')
-local handlers = require('muwiki.handlers')
-local url_handlers = require('muwiki.links.url_handlers')
-
-local M = {}
-
-local function get_wiki_root_or_notify()
- local wiki_root = config.wiki_root(0)
- if not wiki_root then
- vim.notify('Not in a wiki buffer', vim.log.levels.ERROR)
- return nil
- end
- return wiki_root
-end
-
-function M.open_link()
- local link = links.get_link()
- if not link then
- vim.notify('No link found under cursor', vim.log.levels.WARN)
- return
- end
-
- if link.type == 'web' then
- url_handlers.handle_web_link(link.target)
- return
- end
-
- local wiki_root = get_wiki_root_or_notify()
- if not wiki_root then
- return
- end
-
- if link.type == 'file' then
- if vim.startswith(link.target, 'file://') then
- url_handlers.handle_file_url(link.target)
- else
- url_handlers.handle_file_link(link.target, wiki_root)
- end
- return
- end
-
- url_handlers.handle_wiki_link(link.target, wiki_root)
-end
-
-function M.open_link_with()
- local link = links.get_link()
- if not link then
- vim.notify('No link found under cursor', vim.log.levels.WARN)
- return
- end
-
- if link.type == 'wiki' then
- vim.notify('Menu not available for wiki links', vim.log.levels.WARN)
- return
- end
-
- local url = link.target
- if link.type == 'file' then
- local wiki_root = get_wiki_root_or_notify()
- if not wiki_root then
- return
- end
- url = files.resolve(url, wiki_root)
- end
-
- local matching_handlers = handlers.get_matching(url)
-
- if #matching_handlers == 0 then
- vim.notify('No handlers available for this URL', vim.log.levels.WARN)
- return
- end
-
- if #matching_handlers == 1 then
- handlers.execute(matching_handlers[1], url)
- return
- end
-
- local handler_names = {}
- for _, handler in ipairs(matching_handlers) do
- table.insert(handler_names, handler.name)
- end
-
- vim.ui.select(handler_names, {
- prompt = 'Open with:',
- }, function(choice, idx)
- if choice and idx then
- handlers.execute(matching_handlers[idx], url)
- end
- end)
-end
-
-return M
diff --git a/lua/muwiki/links/url_handlers.lua b/lua/muwiki/links/url_handlers.lua
deleted file mode 100644
index f84715a..0000000
--- a/lua/muwiki/links/url_handlers.lua
+++ /dev/null
@@ -1,71 +0,0 @@
-local config = require('muwiki.config')
-local paths = require('muwiki.paths')
-local files = require('muwiki.files')
-local fs = require('muwiki.fs')
-
-local M = {}
-
-function M.handle_web_link(url)
- if not config.options.use_external_handlers then
- return
- end
- files.open_external(url)
-end
-
-local function resolve_file_url(url)
- local path = paths.strip_file_protocol(url)
- local resolved_path
-
- local path_type = paths.get_path_type(path)
-
- if path_type == 'absolute' then
- resolved_path = path
- elseif path_type == 'home' then
- resolved_path = vim.fs.normalize(path)
- else
- local current_dir = vim.fs.dirname(vim.api.nvim_buf_get_name(0))
- resolved_path = paths.resolve_relative(path, current_dir)
- end
-
- return 'file://' .. vim.fs.normalize(resolved_path)
-end
-
-function M.handle_file_url(url)
- if not config.options.use_external_handlers then
- return
- end
-
- local absolute_url = resolve_file_url(url)
- files.open_external(absolute_url)
-end
-
-function M.handle_file_link(target, wiki_root)
- local ok, file_path = pcall(files.resolve, target, wiki_root)
- if not ok then
- vim.notify(string.format('Cannot resolve path: %s', target), vim.log.levels.ERROR)
- return
- end
-
- if not fs.file_exists(file_path) then
- vim.notify(string.format('File not found: %s', file_path), vim.log.levels.ERROR)
- return
- end
-
- local ext = file_path:match('%.([^%.]+)$') or ''
- if not files.is_text_file(ext) then
- if not config.options.use_external_handlers then
- return
- end
- files.open_external(file_path)
- return
- end
-
- files.open_in_buffer(file_path)
-end
-
-function M.handle_wiki_link(target, wiki_root)
- local file_path = files.resolve(target, wiki_root)
- files.open_wiki_file(file_path)
-end
-
-return M
diff --git a/lua/muwiki/paths.lua b/lua/muwiki/paths.lua
index aa07776..f679888 100644
--- a/lua/muwiki/paths.lua
+++ b/lua/muwiki/paths.lua
@@ -1,4 +1,3 @@
-
local M = {}
function M.get_path_type(path)
@@ -11,40 +10,16 @@ function M.get_path_type(path)
end
end
-function M.resolve_relative(path, base)
- local result
-
- if vim.startswith(path, './') then
- result = vim.fs.joinpath(base, path:sub(3))
- elseif vim.startswith(path, '../') then
- local current_base = base
- local remaining = path
-
- while vim.startswith(remaining, '../') do
- current_base = vim.fs.dirname(current_base)
- remaining = remaining:sub(4)
- end
-
- result = vim.fs.joinpath(current_base, remaining)
- else
- result = vim.fs.joinpath(base, path)
- end
-
- return vim.fs.normalize(result)
-end
-
function M.resolve(filepath, current_file)
local path_type = M.get_path_type(filepath)
- if path_type == 'absolute' then
- return vim.fs.normalize(filepath)
- elseif path_type == 'home' then
- return vim.fs.normalize(filepath)
- else
+ if path_type == 'relative' then
local base = current_file and vim.fs.dirname(current_file)
- or vim.fs.dirname(vim.api.nvim_buf_get_name(0))
- return M.resolve_relative(filepath, base)
+ or vim.fs.dirname(vim.api.nvim_buf_get_name(0))
+ filepath = vim.fs.joinpath(base, filepath)
end
+
+ return vim.fs.normalize(filepath)
end
function M.strip_file_protocol(url)
diff --git a/lua/muwiki/templates.lua b/lua/muwiki/template.lua
index c8dcd13..d8eca16 100644
--- a/lua/muwiki/templates.lua
+++ b/lua/muwiki/template.lua
@@ -1,5 +1,5 @@
local config = require('muwiki.config')
-local fs = require('muwiki.fs')
+local io_module = require('muwiki.io')
local M = {}
@@ -16,7 +16,7 @@ local function process_template(template, title)
end
function M.init_file(bufnr, filepath)
- if fs.file_exists(filepath) then
+ if io_module.file_exists(filepath) then
return
end