Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,11 @@ dotmd/

When you create a new note, **dotmd.nvim**:

1. Prompts for a file name or path. (See [Input patterns](#input-patterns))
2. Generates a file path inside the configured notes folder.
3. Optionally applies a notes template.
4. Opens the file in a vertical/horizontal split or current window.
1. Prompts for select/create a subdirectory or use the base directory.
2. Prompts for a file name or path. (See [Input patterns](#input-patterns))
3. Generates a file path inside the configured notes folder.
4. Optionally applies a notes template.
5. Opens the file in a vertical/horizontal split or current window.

#### Input patterns

Expand Down
9 changes: 5 additions & 4 deletions doc/dotmd.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,11 @@ FILE CREATION ~

When you create a new note, **dotmd.nvim**

1. Promptsfor a file name or path. (See |dotmd.nvim-input-patterns|)
2. Generates a file path inside the configured notes folder.
3. Optionally applies a notes template.
4. Opens the file in a vertical/horizontal split or current window.
1. Promptsfor select/create a subdirectory or use the base directory.
2. Prompts for a file name or path. (See |dotmd.nvim-input-patterns|)
3. Generates a file path inside the configured notes folder.
4. Optionally applies a notes template.
5. Opens the file in a vertical/horizontal split or current window.


INPUT PATTERNS
Expand Down
49 changes: 28 additions & 21 deletions lua/dotmd/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,44 @@ local M = {}
function M.create_note(opts)
local utils = require("dotmd.utils")
local directories = require("dotmd.directories")
local config = require("dotmd.config").config
local prompt = require("dotmd.prompt")

opts = utils.merge_default_create_file_opts(opts)

vim.ui.input({
prompt = "Note name/path: ",
default = "",
}, function(name_or_path)
if not name_or_path or name_or_path == "" then
local base_notes_dir = directories.get_notes_dir()

local subdirs = directories.get_subdirs_recursive(base_notes_dir)

vim.ui.select(subdirs, {
prompt = "Select a subdirectory to create the note in: ",
}, function(selected)
if not selected or selected == "" then
return
end

local base_path = directories.get_notes_dir()
local subdir = vim.fn.fnamemodify(name_or_path, ":h")
local filename = vim.fn.fnamemodify(name_or_path, ":t")
local base_path

if subdir ~= "." then
base_path = base_path .. subdir .. "/"
utils.ensure_directory(base_path)
end
if selected == "[Create new subdirectory]" then
vim.ui.input(
{ prompt = "Enter new subdirectory name: ", default = "" },
function(new_subdir)
if not new_subdir or new_subdir == "" then
return
end

local formatted_name = utils.format_filename(filename)
local note_path = utils.get_unique_filepath(base_path, formatted_name)
local display_name = utils.is_path_like(name_or_path)
and utils.deformat_filename(filename)
or name_or_path
local new_base_path = base_notes_dir .. new_subdir .. "/"

utils.write_file(note_path, display_name, config.templates.notes)
prompt.input_note_name(new_base_path, opts)
end
)
else
if selected == "[base directory]" then
base_path = base_notes_dir
else
base_path = base_notes_dir .. selected .. "/"
end

if opts.open then
utils.open_file(note_path, opts)
prompt.input_note_name(base_path, opts)
end
end)
end
Expand Down
32 changes: 32 additions & 0 deletions lua/dotmd/directories.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,36 @@ function M.get_picker_dirs(opts)
return dirs
end

--- Get subdirectories from a base path
---@param base_path string The base path to get subdirectories from
---@return string[] subdirs The subdirectories
function M.get_subdirs_recursive(base_path)
local subdirs = {}

local function scan_dir(current_path, prefix)
prefix = prefix or ""
local scandir = vim.uv.fs_scandir(current_path)
if scandir then
while true do
local name, type = vim.uv.fs_scandir_next(scandir)
if not name then
break
end
if type == "directory" then
local relative_dir = prefix .. name
table.insert(subdirs, relative_dir)
scan_dir(current_path .. "/" .. name, relative_dir .. "/")
end
end
end
end

scan_dir(base_path, "")

table.insert(subdirs, 1, "[Create new subdirectory]")
table.insert(subdirs, 2, "[base directory]")

return subdirs
end

return M
41 changes: 41 additions & 0 deletions lua/dotmd/prompt.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
local M = {}

--- Input a note name/path
---@param opts DotMd.CreateFileOpts Options for creating the file
---@return nil
function M.input_note_name(base_path, opts)
vim.ui.input({
prompt = "Note name/path: ",
default = "",
}, function(name_or_path)
local utils = require("dotmd.utils")
local config = require("dotmd.config").config

if not name_or_path or name_or_path == "" then
return
end

local subdir = vim.fn.fnamemodify(name_or_path, ":h")
local filename = vim.fn.fnamemodify(name_or_path, ":t")

if subdir ~= "." then
base_path = base_path .. subdir .. "/"
utils.ensure_directory(base_path)
end

local formatted_name = utils.format_filename(filename)
local note_path = utils.get_unique_filepath(base_path, formatted_name)

local display_name = utils.is_path_like(name_or_path)
and utils.deformat_filename(filename)
or name_or_path

utils.write_file(note_path, display_name, config.templates.notes)

if opts.open then
utils.open_file(note_path, opts)
end
end)
end

return M
47 changes: 47 additions & 0 deletions tests/directories_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,51 @@ describe("dotmd.directories module", function()
end
)
end)

describe("get_subdirs_recursive", function()
local tmp_dir = nil

-- Create a temporary directory structure for testing.
before_each(function()
-- Create a unique temporary directory.
tmp_dir = vim.fn.tempname()
vim.fn.mkdir(tmp_dir, "p")

-- Create subdirectories:
-- tmp_dir/sub1
-- tmp_dir/sub1/nested
-- tmp_dir/sub2
vim.fn.mkdir(tmp_dir .. "/sub1", "p")
vim.fn.mkdir(tmp_dir .. "/sub1/nested", "p")
vim.fn.mkdir(tmp_dir .. "/sub2", "p")
end)

-- Clean up the temporary directory after each test.
after_each(function()
-- Recursively remove the temporary directory.
os.execute("rm -rf " .. tmp_dir)
end)

it(
"returns subdirectories recursively with expected headers",
function()
local subdirs = directories.get_subdirs_recursive(tmp_dir)

-- Verify that the two header strings are the first two items.
assert.equals("[Create new subdirectory]", subdirs[1])
assert.equals("[base directory]", subdirs[2])

-- Since the order of subdirectories from the filesystem might not be guaranteed,
-- check that the expected paths are present in the returned list.
local found = {}
for i = 3, #subdirs do
found[subdirs[i]] = true
end

assert.is_true(found["sub1"])
assert.is_true(found["sub1/nested"])
assert.is_true(found["sub2"])
end
)
end)
end)