aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md28
-rw-r--r--doc/muwiki.txt134
-rw-r--r--doc/tags1
-rw-r--r--lua/muwiki/config.lua7
-rw-r--r--lua/muwiki/external.lua29
-rw-r--r--lua/muwiki/health.lua4
-rw-r--r--lua/muwiki/init.lua2
-rw-r--r--lua/muwiki/io.lua161
-rw-r--r--lua/muwiki/links.lua112
-rw-r--r--lua/muwiki/paths.lua20
-rw-r--r--lua/muwiki/template.lua35
-rw-r--r--lua/muwiki/utils.lua57
12 files changed, 210 insertions, 380 deletions
diff --git a/README.md b/README.md
index 56c3ea6..c43671a 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,6 @@ A lightweight wiki plugin for Neovim using standard markdown syntax.
- Standard markdown links `[text](url)`
- Multiple wiki directories
- External link handlers
-- Automatic template for new page
- Link navigation with custom keymaps
See `:help muwiki` for complete documentation and configuration options.
@@ -37,14 +36,16 @@ Using [lazy.nvim](https://github.com/folke/lazy.nvim):
local muwiki = require('muwiki')
muwiki.setup(opts)
- local group = vim.api.nvim_create_augroup("MuWikiKeymaps", { clear = true })
+ local group = vim.api.nvim_create_augroup("muwiki", { clear = true })
+ -- Setup wiki keymaps for markdown files
vim.api.nvim_create_autocmd("FileType", {
group = group,
pattern = "markdown",
- callback = function(ev)
- if not muwiki.wiki_root(ev.buf) then return end
- local keymap_opts = { buffer = ev.buf, silent = true, nowait = true }
+ callback = function(args)
+ if not muwiki.wiki_root(args.buf) then return end
+
+ local keymap_opts = { buffer = args.buf, silent = true, nowait = true }
vim.keymap.set('n', '<CR>', muwiki.open_link, keymap_opts)
vim.keymap.set('n', '<Tab>', muwiki.next_link, keymap_opts)
vim.keymap.set('n', '<S-Tab>', muwiki.prev_link, keymap_opts)
@@ -52,6 +53,23 @@ Using [lazy.nvim](https://github.com/folke/lazy.nvim):
vim.keymap.set('n', '<leader>oo', muwiki.open_link_with, keymap_opts)
end,
})
+
+ -- Auto-create parent directories when saving files in wiki
+ vim.api.nvim_create_autocmd("BufWritePre", {
+ group = group,
+ callback = function(args)
+ local wiki_root = muwiki.wiki_root(args.buf)
+ if not wiki_root then return end
+
+ local file = args.file
+ if not vim.startswith(file, wiki_root) then return end
+
+ local dir = vim.fn.fnamemodify(file, ":h")
+ if vim.fn.isdirectory(dir) == 0 then
+ vim.fn.mkdir(dir, "p")
+ end
+ end,
+ })
end,
}
```
diff --git a/doc/muwiki.txt b/doc/muwiki.txt
index 4576388..878095d 100644
--- a/doc/muwiki.txt
+++ b/doc/muwiki.txt
@@ -12,7 +12,6 @@ CONTENTS *muwiki-contents*
5. Keymaps ................................ |muwiki-keymaps|
6. Link Format ............................ |muwiki-link-format|
7. External Handlers ...................... |muwiki-external-handlers|
-8. Templates .............................. |muwiki-templates|
==============================================================================
1. INTRODUCTION *muwiki-introduction*
@@ -24,7 +23,6 @@ Features:~
- Standard markdown links `[text](url)`
- Multiple wiki directories support
- External link handlers for custom URL/file opening
-- Automatic templates for new pages
- Link navigation with custom keymaps
Requirements:~
@@ -51,20 +49,39 @@ Using lazy.nvim:~
local muwiki = require('muwiki')
muwiki.setup(opts)
- local group = vim.api.nvim_create_augroup("MuWikiKeymaps", { clear = true })
+ local group = vim.api.nvim_create_augroup("muwiki", { clear = true })
+ -- Setup wiki keymaps for markdown files
vim.api.nvim_create_autocmd("FileType", {
group = group,
pattern = "markdown",
- callback = function(ev)
- if not muwiki.wiki_root(ev.buf) then return end
- local keymap_opts = { buffer = ev.buf, silent = true, nowait = true }
+ callback = function(args)
+ if not muwiki.wiki_root(args.buf) then return end
+
+ local keymap_opts = { buffer = args.buf, silent = true, nowait = true }
vim.keymap.set('n', '<CR>', muwiki.open_link, keymap_opts)
vim.keymap.set('n', '<Tab>', muwiki.next_link, keymap_opts)
vim.keymap.set('n', '<S-Tab>', muwiki.prev_link, keymap_opts)
vim.keymap.set('v', '<CR>', muwiki.create_link, keymap_opts)
end,
})
+
+ -- Auto-create parent directories when saving files in wiki
+ vim.api.nvim_create_autocmd("BufWritePre", {
+ group = group,
+ callback = function(args)
+ local wiki_root = muwiki.wiki_root(args.buf)
+ if not wiki_root then return end
+
+ local file = args.file
+ if not vim.startswith(file, wiki_root) then return end
+
+ local dir = vim.fn.fnamemodify(file, ":h")
+ if vim.fn.isdirectory(dir) == 0 then
+ vim.fn.mkdir(dir, "p")
+ end
+ end,
+ })
end,
}
<
@@ -79,15 +96,6 @@ Configuration Options:~
index_file Name of the wiki index file
Default: 'index.md'
- date_fmt Date format string for templates
- Default: '%Y-%m-%d'
-
- use_template Enable automatic templates for new pages
- Default: false
-
- template Template content with placeholders
- See |muwiki-templates|
-
use_external_handlers Enable external URL/file handlers
Default: false
@@ -101,15 +109,6 @@ Configuration Options:~
to force editor opening.
Default: { 'md', 'txt' }
- create_missing_dirs Automatically create missing parent directories
- when opening or creating wiki files.
- Values:
- false - Don't create directories (default)
- 'notify' - Create and show notification
- 'prompt' - Ask before creating
- Directories are only created within wiki root.
- Default: false
-
Example:~
>lua
{
@@ -124,15 +123,6 @@ Example:~
{ name = 'test', path = '~/wiki_test' },
},
index_file = 'index.md',
- create_missing_dirs = 'notify',
- date_fmt = '%Y-%m-%d',
- use_template = true,
- template = [[
- ---
- title: ${title}
- date: ${date}
- ---
- ]],
text_extensions = { 'md', 'txt' },
use_external_handlers = true,
external_handlers = {
@@ -168,14 +158,16 @@ Example:~
local muwiki = require('muwiki')
muwiki.setup(opts)
- local group = vim.api.nvim_create_augroup("MuWikiKeymaps", { clear = true })
+ local group = vim.api.nvim_create_augroup("muwiki", { clear = true })
+ -- Setup wiki keymaps for markdown files
vim.api.nvim_create_autocmd("FileType", {
group = group,
pattern = "markdown",
- callback = function(ev)
- if not muwiki.wiki_root(ev.buf) then return end
- local keymap_opts = { buffer = ev.buf, silent = true, nowait = true }
+ callback = function(args)
+ if not muwiki.wiki_root(args.buf) then return end
+
+ local keymap_opts = { buffer = args.buf, silent = true, nowait = true }
vim.keymap.set('n', '<CR>', muwiki.open_link, keymap_opts)
vim.keymap.set('n', '<Tab>', muwiki.next_link, keymap_opts)
vim.keymap.set('n', '<S-Tab>', muwiki.prev_link, keymap_opts)
@@ -183,6 +175,23 @@ Example:~
vim.keymap.set('n', '<leader>oo', muwiki.open_link_with, keymap_opts)
end,
})
+
+ -- Auto-create parent directories when saving files in wiki
+ vim.api.nvim_create_autocmd("BufWritePre", {
+ group = group,
+ callback = function(args)
+ local wiki_root = muwiki.wiki_root(args.buf)
+ if not wiki_root then return end
+
+ local file = args.file
+ if not vim.startswith(file, wiki_root) then return end
+
+ local dir = vim.fn.fnamemodify(file, ":h")
+ if vim.fn.isdirectory(dir) == 0 then
+ vim.fn.mkdir(dir, "p")
+ end
+ end,
+ })
end,
}
<
@@ -277,14 +286,16 @@ Configure keymaps using an autocmd to ensure they only apply within wiki
directories: >lua
local muwiki = require('muwiki')
- local group = vim.api.nvim_create_augroup("MuWikiKeymaps", { clear = true })
+ local group = vim.api.nvim_create_augroup("muwiki", { clear = true })
+ -- Setup wiki keymaps for markdown files
vim.api.nvim_create_autocmd("FileType", {
group = group,
pattern = "markdown",
- callback = function(ev)
- if not muwiki.wiki_root(ev.buf) then return end
- local opts = { buffer = ev.buf, silent = true, nowait = true }
+ callback = function(args)
+ if not muwiki.wiki_root(args.buf) then return end
+
+ local opts = { buffer = args.buf, silent = true, nowait = true }
vim.keymap.set('n', '<CR>', muwiki.open_link, opts)
vim.keymap.set('n', '<Tab>', muwiki.next_link, opts)
vim.keymap.set('n', '<S-Tab>', muwiki.prev_link, opts)
@@ -292,6 +303,23 @@ directories: >lua
vim.keymap.set('n', '<leader>oo', muwiki.open_link_with, opts)
end,
})
+
+ -- Auto-create parent directories when saving files in wiki
+ vim.api.nvim_create_autocmd("BufWritePre", {
+ group = group,
+ callback = function(args)
+ local wiki_root = muwiki.wiki_root(args.buf)
+ if not wiki_root then return end
+
+ local file = args.file
+ if not vim.startswith(file, wiki_root) then return end
+
+ local dir = vim.fn.fnamemodify(file, ":h")
+ if vim.fn.isdirectory(dir) == 0 then
+ vim.fn.mkdir(dir, "p")
+ end
+ end,
+ })
<
Note: Actions check if the buffer is within a configured wiki directory and
notify the user if not.
@@ -409,30 +437,6 @@ Example: Open PNG files in Neovim (as text/hex) instead of external viewer:~
text_extensions = { 'md', 'txt', 'png' }
<
==============================================================================
-8. TEMPLATES *muwiki-templates*
-
-Automatic templates can be applied when creating new wiki pages.
-
-Enable templates:~
->lua
- require("muwiki").setup({
- use_template = true,
- })
-<
-Template Placeholders:~
-
- ${title} Page title (derived from filename)
- ${date} Current date (formatted with `date_fmt`)
-
-Default Template:~
->lua
- template = [[
----
-title: ${title}
-date: ${date}
----
-]]
-<
==============================================================================
HEALTH CHECKING *muwiki-health*
diff --git a/doc/tags b/doc/tags
index f52890d..300649b 100644
--- a/doc/tags
+++ b/doc/tags
@@ -7,7 +7,6 @@ muwiki-installation muwiki.txt /*muwiki-installation*
muwiki-introduction muwiki.txt /*muwiki-introduction*
muwiki-keymaps muwiki.txt /*muwiki-keymaps*
muwiki-link-format muwiki.txt /*muwiki-link-format*
-muwiki-templates muwiki.txt /*muwiki-templates*
muwiki.next_link() muwiki.txt /*muwiki.next_link()*
muwiki.open_index() muwiki.txt /*muwiki.open_index()*
muwiki.open_link() muwiki.txt /*muwiki.open_link()*
diff --git a/lua/muwiki/config.lua b/lua/muwiki/config.lua
index 1e7e3de..1e04d4a 100644
--- a/lua/muwiki/config.lua
+++ b/lua/muwiki/config.lua
@@ -3,12 +3,6 @@ local M = {}
M.options = {
dirs = nil,
index_file = 'index.md',
- date_fmt = '%Y-%m-%d',
- use_template = false,
- template = [[
-title: ${title}
-date: ${date}
-]],
text_extensions = { 'md', 'txt' },
use_external_handlers = false,
external_handlers = {
@@ -18,7 +12,6 @@ date: ${date}
pattern = '.*',
},
},
- create_missing_dirs = false,
}
local function dir_exists(path)
diff --git a/lua/muwiki/external.lua b/lua/muwiki/external.lua
index cf26aca..9ea83b5 100644
--- a/lua/muwiki/external.lua
+++ b/lua/muwiki/external.lua
@@ -27,33 +27,4 @@ function M.execute(handler, url)
end
end
-function M.matches(handler, url)
- local pattern = handler.pattern
-
- if pattern == nil then
- return true
- end
-
- if type(pattern) == 'string' then
- return url:match(pattern) ~= nil
- end
-
- for _, p in ipairs(pattern) do
- if url:match(p) then
- return true
- end
- end
- return false
-end
-
-function M.get_matching(url)
- local matching = {}
- for _, handler in ipairs(config.options.external_handlers) do
- if M.matches(handler, url) then
- table.insert(matching, handler)
- end
- end
- return matching
-end
-
return M
diff --git a/lua/muwiki/health.lua b/lua/muwiki/health.lua
index 2dfd45b..22c9747 100644
--- a/lua/muwiki/health.lua
+++ b/lua/muwiki/health.lua
@@ -1,5 +1,5 @@
-local io_module = require('muwiki.io')
+local utils = require('muwiki.utils')
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 io_module.dir_exists(dir.path) then
+ if utils.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 5538d91..a6997a7 100644
--- a/lua/muwiki/init.lua
+++ b/lua/muwiki/init.lua
@@ -27,7 +27,7 @@ function M.create_link()
end
function M.open_index(name)
- require('muwiki.io').open_index(name)
+ require('muwiki.utils').open_index(name)
end
function M.wiki_root(bufnr)
diff --git a/lua/muwiki/io.lua b/lua/muwiki/io.lua
deleted file mode 100644
index e86fb2e..0000000
--- a/lua/muwiki/io.lua
+++ /dev/null
@@ -1,161 +0,0 @@
-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
index 990ecb1..55ce692 100644
--- a/lua/muwiki/links.lua
+++ b/lua/muwiki/links.lua
@@ -1,6 +1,6 @@
local config = require('muwiki.config')
local paths = require('muwiki.paths')
-local io_module = require('muwiki.io')
+local utils = require('muwiki.utils')
local external = require('muwiki.external')
local M = {}
@@ -72,50 +72,6 @@ local function resolve_file_url(url)
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
@@ -133,7 +89,9 @@ function M.open_link()
end
if link.type == 'web' then
- M.handle_web_link(link.target)
+ if config.options.use_external_handlers then
+ external.open(link.target)
+ end
return
end
@@ -144,14 +102,38 @@ function M.open_link()
if link.type == 'file' then
if vim.startswith(link.target, 'file://') then
- M.handle_file_url(link.target)
+ if config.options.use_external_handlers then
+ local absolute_url = resolve_file_url(link.target)
+ external.open(absolute_url)
+ end
else
- M.handle_file_link(link.target, wiki_root)
+ local ok, file_path = pcall(utils.resolve, link.target, wiki_root)
+ if not ok then
+ vim.notify(string.format('Cannot resolve path: %s', link.target), vim.log.levels.ERROR)
+ return
+ end
+
+ if not utils.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 utils.is_text_file(ext) then
+ if config.options.use_external_handlers then
+ external.open(file_path)
+ end
+ return
+ end
+
+ utils.open_in_buffer(file_path)
end
return
end
- M.handle_wiki_link(link.target, wiki_root)
+ -- wiki link
+ local file_path = utils.resolve(link.target, wiki_root)
+ utils.open_wiki_file(file_path)
end
function M.open_link_with()
@@ -172,10 +154,32 @@ function M.open_link_with()
if not wiki_root then
return
end
- url = io_module.resolve(url, wiki_root)
+ url = utils.resolve(url, wiki_root)
end
- local matching_handlers = external.get_matching(url)
+ -- Find matching handlers for URL
+ local function handler_matches(handler, url)
+ local pattern = handler.pattern
+ if pattern == nil then
+ return true
+ end
+ if type(pattern) == 'string' then
+ return url:match(pattern) ~= nil
+ end
+ for _, p in ipairs(pattern) do
+ if url:match(p) then
+ return true
+ end
+ end
+ return false
+ end
+
+ local matching_handlers = {}
+ for _, handler in ipairs(config.options.external_handlers) do
+ if handler_matches(handler, url) then
+ table.insert(matching_handlers, handler)
+ end
+ end
if #matching_handlers == 0 then
vim.notify('No handlers available for this URL', vim.log.levels.WARN)
@@ -223,7 +227,7 @@ function M.create_link()
end
local selected_text = region[1]
- local normalized = io_module.normalize_filename(selected_text)
+ local normalized = utils.normalize_filename(selected_text)
local link_target = normalized .. '.md'
local link_text = string.format('[%s](%s)', selected_text, link_target)
@@ -256,8 +260,8 @@ function M.create_link()
return
end
- local target_path = io_module.resolve(link_target, wiki_root)
- io_module.open_wiki_file(target_path)
+ local target_path = utils.resolve(link_target, wiki_root)
+ utils.open_wiki_file(target_path)
end
local function jump_link(direction)
diff --git a/lua/muwiki/paths.lua b/lua/muwiki/paths.lua
index f679888..c2f8fdb 100644
--- a/lua/muwiki/paths.lua
+++ b/lua/muwiki/paths.lua
@@ -26,26 +26,6 @@ function M.strip_file_protocol(url)
return url:gsub('^file://', '')
end
-function M.is_within_wiki(filepath, wiki_root)
- local real_path = vim.fn.resolve(filepath)
- local real_root = vim.fn.resolve(wiki_root)
-
- local normalized_path = vim.fs.normalize(real_path)
- local normalized_root = vim.fs.normalize(real_root)
-
- return vim.startswith(normalized_path, normalized_root)
-end
-
-function M.validate_within_wiki(resolved_path, wiki_root, original_path)
- if not M.is_within_wiki(resolved_path, wiki_root) then
- vim.notify(
- string.format('Warning: Resolved path outside wiki root: %s', original_path),
- vim.log.levels.WARN
- )
- end
- return resolved_path
-end
-
local ALLOWED_SCHEMES = {
http = true,
https = true,
diff --git a/lua/muwiki/template.lua b/lua/muwiki/template.lua
deleted file mode 100644
index d8eca16..0000000
--- a/lua/muwiki/template.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local config = require('muwiki.config')
-local io_module = require('muwiki.io')
-
-local M = {}
-
-local function process_template(template, title)
- local date_fmt = config.options.date_fmt or '%Y-%m-%d'
- local date = os.date(date_fmt)
- local result = template:gsub('${title}', title):gsub('${date}', date)
-
- if not result:match('\n$') then
- result = result .. '\n'
- end
-
- return result
-end
-
-function M.init_file(bufnr, filepath)
- if io_module.file_exists(filepath) then
- return
- end
-
- local filename = vim.fs.basename(filepath)
-
- if config.options.use_template then
- local title = filename:gsub('%.md$', ''):gsub('_', ' ')
- local content = process_template(config.options.template, title)
- local lines = vim.split(content, '\n', { plain = true })
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
- end
-
- vim.notify(string.format('%s (unsaved)', filename), vim.log.levels.INFO)
-end
-
-return M
diff --git a/lua/muwiki/utils.lua b/lua/muwiki/utils.lua
new file mode 100644
index 0000000..af22c8e
--- /dev/null
+++ b/lua/muwiki/utils.lua
@@ -0,0 +1,57 @@
+local config = require('muwiki.config')
+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.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)
+ local path = paths.strip_file_protocol(filepath)
+ return paths.resolve(path, wiki_root)
+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)
+ M.open_in_buffer(filepath)
+end
+
+return M