aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md44
-rw-r--r--lua/denote/api.lua109
-rw-r--r--lua/denote/cmd.lua35
-rw-r--r--lua/denote/config.lua30
-rw-r--r--lua/denote/init.lua18
-rw-r--r--lua/denote/internal.lua207
-rw-r--r--lua/denote/util.lua41
7 files changed, 212 insertions, 272 deletions
diff --git a/README.md b/README.md
index b0db470..c86be17 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,31 @@
# `denote.nvim`
-`denote.nvim` is a plugins for creating notes without any external dependencies. Main inspiration for this project was emacs package called `Denote`.
+This is a fork of HumanEntity's `denote.nvim`, modified to suit my personal preferences and be more accurate to the original emacs `denote` filename format.
+There is no support for frontmatter, signatures, or any other `denote` features because I don't use them. I just like the filenaming scheme. This is just a simple command I use to create new markdown notes with `denote` filenaming.
-# Installation
+You can read more about the `denote` file-naming scheme here:
+https://protesilaos.com/emacs/denote#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d
+
+# Installation / Config
+
+Example config via [lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
{
- "HumanEntity/denote.nvim",
- build = "mkdir -p ~/.denote/",
- cmd = "Denote",
+ "DefaultGen/denote.nvim",
+ opts = {
+ ext = "md",
+ dir = "~/notes/",
+ new_heading_on_retitle = true,
+ },
}
```
-This takes care of installing, lazy loading and creating note directory for `denote`. Denote has no external dependencies but I recommend you use `telescope-ui-select.nvim` plugin for better ui.
+`ext` is the file extension for your notes (e.g. md, org, norg)
+`dir` is your notes directory. Make sure you create it beforehand.
+`new_heading_on_retitle` determines whether `denote.nvim` will replace the first line with a new heading when you retitle a note. It will only do this if the first line is a heading to begin with.
+
# Usage
@@ -23,9 +35,15 @@ This takes care of installing, lazy loading and creating note directory for `den
To create use `note` sub command. It will will prompt for note name and tags. Tags are space separated.
-### Searching for notes
+### Change note title
+
+To change the title, use the `retitle` sub command. It will prompt you for a new title, then update both the filename and first line (if configured).
+
+I don't use frontmatter and all my markdown notes start with a heading that includes the title, so the default behavior is to swap the first line with the new title. You can disable this in the config so it only changes the filename.
-To search for note use `search` sub command. It will prompt for date in YEAR MONTH DAY format, name and tags.
+### Change note tags
+
+To change the tags, use the `retag` sub command. This will prompt you for new, comma-separated tags. All this does is change the filename because I don't use frontmatter.
## `api` way
@@ -48,13 +66,9 @@ One thing to note is that you can use the api just like the command just don't p
To create the note use `note` function.
```lua
-api.note(name, tags)
+api.note(options, name, tags)
```
-### Searching for notes
-
-To search for note use `search` function.`date` is table with year, month and day field, `name` just a string and `tags` list of tags.
+# License
-```lua
-api.search(date,name,tags)
-```
+MIT
diff --git a/lua/denote/api.lua b/lua/denote/api.lua
index 277827f..e88a333 100644
--- a/lua/denote/api.lua
+++ b/lua/denote/api.lua
@@ -1,76 +1,57 @@
local M = {}
+
local internal = require("denote.internal")
local util = require("denote.util")
-local config = require("denote.config")
+---@param options table
---@param name string|nil
---@param tags table|nil
-function M.note(name, tags)
- if not name then
- vim.ui.input({ prompt = "Note name: " }, function(input)
- name = input
- end)
- end
-
- if not tags then
- vim.ui.input({ prompt = "Enter tags: " }, function(input)
- if input ~= "" and input then
- tags = util.splitspace(input)
- end
- end)
- end
-
- if name == "" then
- error("Didn't specify name")
- end
-
- internal.note(name, tags)
+function M.note(options, name, tags)
+ if not name then
+ vim.ui.input({ prompt = "Note title: " }, function(input)
+ name = input
+ end)
+ end
+ if not tags then
+ vim.ui.input({ prompt = "Tags: " }, function(input)
+ if input ~= "" and input then
+ tags = util.splitspace(input)
+ end
+ end)
+ end
+ internal.note(options, name, tags)
end
----@param date DenoteDate|nil
----@param name string|nil
----@param tags table|nil
-function M.search(date, name, tags)
- if not date then
- vim.ui.input({ prompt = "Date: " }, function(input)
- local split = util.splitspace(input)
- if split[0] then
- date = {}
- date.year = split[0]
- if split[1] then
- date.month = split[1]
- if split[2] then
- date.day = split[2]
- end
- end
- end
- end)
- end
-
- if not name then
- vim.ui.input({ prompt = "Name: " }, function(input)
- name = input
- end)
- end
-
- if not tags then
- vim.ui.input({ prompt = "Tags: " }, function(input)
- if input == "" then
- return
- end
- tags = util.splitstring(input, " ")
- end)
- end
-
- local status = internal.search(date, name, tags, function(input)
- if input then
- vim.cmd("e " .. config.vault.dir .. "/" .. input)
- end
- end)
+---@param options table
+---@param filename string|nil
+---@param new_title string|nil
+function M.retitle(options, filename, new_title)
+ if not filename then
+ filename = vim.fn.expand("%")
+ end
+ if not new_title then
+ vim.ui.input({ prompt = "New title: " }, function(input)
+ new_title = input
+ end)
+ end
+ internal.retitle(options, filename, new_title)
+end
- if not status then
- print("Error opening file")
- end
+---@param options table
+---@param filename string|nil
+---@param new_tags table|nil
+function M.retag(options, filename, new_tags)
+ if not filename then
+ filename = vim.fn.expand("%")
+ end
+ if not new_tags then
+ vim.ui.input({ prompt = "New tags: " }, function(input)
+ if input ~= "" and input then
+ new_tags = util.splitspace(input)
+ end
+ end)
+ end
+ internal.retag(options, filename, new_tags)
end
return M
diff --git a/lua/denote/cmd.lua b/lua/denote/cmd.lua
index 6489f0c..91ca96e 100644
--- a/lua/denote/cmd.lua
+++ b/lua/denote/cmd.lua
@@ -1,23 +1,26 @@
local M = {
- commands = { "note", "search" },
+ commands = { "note", "retitle", "retag" },
}
+
local api = require("denote.api")
-function M.load_cmd()
- vim.api.nvim_create_user_command("Denote", function(opts)
- if opts.fargs[1] == "note" then
- api.note()
- elseif opts.fargs[1] == "search" then
- api.search()
- else
- error("Unsupported operation " .. opts.fargs[1])
- end
- end, {
- nargs = 1,
- complete = function()
- return { "note", "search" }
- end,
- })
+function M.load_cmd(options)
+ vim.api.nvim_create_user_command("Denote", function(opts)
+ if opts.fargs[1] == "note" then
+ api.note(options)
+ elseif opts.fargs[1] == "retitle" then
+ api.retitle(options)
+ elseif opts.fargs[1] == "retag" then
+ api.retag(options)
+ else
+ error("Unsupported operation " .. opts.fargs[1])
+ end
+ end, {
+ nargs = 1,
+ complete = function()
+ return M.commands
+ end,
+ })
end
return M
diff --git a/lua/denote/config.lua b/lua/denote/config.lua
index fce9a50..fe0d6ee 100644
--- a/lua/denote/config.lua
+++ b/lua/denote/config.lua
@@ -1,27 +1,11 @@
----@class DenoteConfigFilename
----@field ext string defaults to "norg"
----@field date_sep string defaults to "_"
----@field name_sep string defaults to "-"
----@field tag_sep string defaults to "="
+local M = {}
----@class DenoteConfigVault
----@field dir string defaults to "~/.denote/"
-
----@class DenoteConfig
----@field filename DenoteConfigFilename
----@field vault DenoteConfigVault
-
----@type DenoteConfig
-local M = {
- filename = {
- ext = "norg",
- date_sep = "_",
- name_sep = "-",
- tag_sep = "=",
- },
- vault = {
- dir = "~/.denote/",
- },
+M.defaults = {
+ ext = "md",
+ dir = "~/notes/",
+ new_heading_on_retitle = true,
}
+M.options = M.defaults
+
return M
diff --git a/lua/denote/init.lua b/lua/denote/init.lua
index 396486f..5e04418 100644
--- a/lua/denote/init.lua
+++ b/lua/denote/init.lua
@@ -1,14 +1,12 @@
-local M = {
- api = require("denote.api"),
- cmd = require("denote.cmd"),
-}
+local M = {}
----@param config DenoteConfig
-function M.setup(config)
- M.cmd.load_cmd()
- if config then
- M.config = config
- end
+local cmd = require("denote.cmd")
+local config = require("denote.config")
+
+---@param options? table user configuration
+function M.setup(options)
+ config.options = vim.tbl_deep_extend("force", config.defaults, options or {})
+ cmd.load_cmd(config.options)
end
return M
diff --git a/lua/denote/internal.lua b/lua/denote/internal.lua
index 83bc251..6ae8785 100644
--- a/lua/denote/internal.lua
+++ b/lua/denote/internal.lua
@@ -1,139 +1,94 @@
local M = {}
-local config = require("denote.config")
-local util = require("denote.util")
-
----@class DenoteDate
----@field year string
----@field month string
----@field day string
-
----@param name string
----@param tags table|nil
----@return string filename format of files in denote.nvim
-function M.file(name, tags)
- local file = ""
-
- local date = tostring(os.date("%Y%m%d"))
-
- local tags_str = ""
-
- if tags then
- for i, tag in pairs(tags) do
- tags_str = tags_str .. tag
- if i < #tags then
- tags_str = tags_str .. config.filename.tag_sep
- end
- end
- end
-
- file = date .. config.filename.date_sep .. config.filename.date_sep .. name
- if tags then
- file = file .. config.filename.name_sep .. config.filename.name_sep .. tags_str
- end
-
- return file .. "." .. config.filename.ext
-end
+---@param options table
---@param name string
---@param tags table|nil
--- Opens your note
-function M.note(name, tags)
- local filename = config.vault.dir .. M.file(name, tags)
-
- -- Echo template
-
- vim.cmd("!mkdir -p " .. config.vault.dir)
- vim.cmd("e " .. filename)
+function M.note(options, name, tags)
+ local path = options.dir
+ local file = ""
+ local date = os.date("%Y%m%dT%H%M%S")
+ local tags_str = ""
+ name = name:gsub("^%s*(.-)%s*$", "%1")
+ name = name:gsub("[^%w%s]","")
+ name = name:gsub("%s","-")
+ if tags then
+ for i, tag in pairs(tags) do
+ tag = tag:gsub("[^%w%s]","")
+ tags_str = tags_str .. tag
+ if i < #tags then
+ tags_str = tags_str .. "_"
+ end
+ end
+ end
+ file = date .. "--" .. name:lower()
+ if tags_str ~= "" then
+ file = file .. "__" .. tags_str:lower()
+ end
+ path = path .. file .. "." .. options.ext
+ vim.cmd("e " .. path)
end
----@param date DenoteDate|nil
----@param name string|nil
----@param tags table|nil
----@param func function
-function M.search(date, name, tags, func)
- local items = {}
- local matcher = ""
-
- if date then
- if date.year then
- matcher = date.year
- else
- matcher = "%d%d%d%d"
- end
- if date.month then
- matcher = matcher .. date.month
- else
- matcher = matcher .. "%d%d"
- end
- if date.day then
- matcher = matcher .. date.day
- else
- matcher = matcher .. "%d%d"
- end
-
- matcher = matcher .. config.filename.date_sep .. config.filename.date_sep
- else
- matcher = "%d+" .. config.filename.date_sep .. config.filename.date_sep
- end
-
- if name then
- matcher = matcher .. name
- else
- matcher = matcher .. ".+"
- end
-
- -- matcher = matcher .. config.filename.name_sep .. "?" .. M.config.filename.name_sep .. "?" .. ".-"
-
- for file in io.popen("ls " .. config.vault.dir):lines() do
- local matched = file:match(matcher)
-
- if matched then
- print("file " .. file)
- items[#items + 1] = file
- end
- end
-
- if not items or #items == 0 then
- return nil
- end
-
- if tags then
- local items_copy = items
- items = {}
- for _, item in pairs(items_copy) do
- local item_tags_pre = M.get_tags(item)
- local item_tags = {}
- for _, i in pairs(item_tags_pre) do
- item_tags[i] = 0
- end
- local good = true
- for _, tag in pairs(tags) do
- if item_tags[tag] == nil then
- good = false
- end
- end
- if good then
- items[#items + 1] = item
- end
- end
- end
-
- vim.ui.select(items, {
- prompt = "Select note",
- }, func)
-
- return true
+---@param options table
+---@param filename string
+---@param new_title string
+--- Retitles the filename and changes the first heading of the note
+function M.retitle(options, filename, new_title)
+ local new_filename = filename:match("^(.*%d%d%d%d%d%d%d%dT%d%d%d%d%d%d).*")
+ local tags = filename:match(".*(__.*)%..*")
+ if new_filename == nil then
+ error("Doesn't look like a Denote filename")
+ end
+ new_title = new_title:gsub("^%s*(.-)%s*$", "%1") -- Trim whitespace
+
+ -- Replace first line with new heading
+ if options.new_heading_on_retitle == true and new_title ~= "" then
+ local first_char = vim.api.nvim_buf_get_lines(0, 0, 1, false)[1]:sub(1, 1)
+ if (first_char == "#" and options.ext == "md") or
+ (first_char == "*" and (options.ext == "org" or options.ext == "norg")) then
+ vim.api.nvim_buf_set_lines(0, 0, 1, false, {first_char .. " " .. new_title})
+ end
+ end
+ new_title = new_title:lower()
+ new_title = new_title:gsub("[^%w%s]","")
+ new_title = new_title:gsub("%s","-")
+ if new_title ~= "" then
+ new_title = "--" .. new_title
+ end
+ new_filename = new_filename .. new_title .. (tags or "") .. "." .. options.ext
+ if filename ~= new_filename then
+ vim.cmd('saveas ' .. new_filename)
+ vim.cmd('silent !rm ' .. filename)
+ end
end
+---@param options table
---@param filename string
----@return table
-function M.get_tags(filename)
- local tags = {}
- local name = util.splitstring(filename, ".")[1]
- for _, s in pairs(util.splitstring(util.splitstring(name, config.filename.name_sep)[3], config.filename.tag_sep)) do
- tags[#tags + 1] = s
- end
- return tags
+---@param new_tags table
+---Replaces the tags in filename with the tags in new_tags
+function M.retag(options, filename, new_tags)
+ local tags_str = ""
+ local new_filename = filename:match("^(.*)__.*$")
+ if new_filename == nil then
+ new_filename = filename:match("^(.*)%..*$")
+ end
+ if new_tags then
+ for i, tag in pairs(new_tags) do
+ tag = tag:gsub("[^%w%s]","")
+ tags_str = tags_str .. tag
+ if i < #new_tags then
+ tags_str = tags_str .. "_"
+ end
+ end
+ end
+ if tags_str ~= "" then
+ new_filename = new_filename .. "__" .. tags_str:lower()
+ end
+ new_filename = new_filename .. "." .. options.ext
+ if filename ~= new_filename then
+ vim.cmd('saveas ' .. new_filename)
+ vim.cmd('silent !rm ' .. filename)
+ end
end
return M
diff --git a/lua/denote/util.lua b/lua/denote/util.lua
index bd237eb..643e2e7 100644
--- a/lua/denote/util.lua
+++ b/lua/denote/util.lua
@@ -1,27 +1,32 @@
local M = {}
+
function M.splitspace(str)
- local chunks = {}
- for substring in str:gmatch("%S+") do
- table.insert(chunks, #chunks, substring)
- end
- return chunks
+ local chunks = {}
+ for substring in str:gmatch("%S+") do
+ table.insert(chunks, #chunks, substring)
+ end
+ return chunks
end
function M.splitstring(str, delim)
- local items = {}
- local fulldelim = nil
- if delim == "." or delim == "-" then
- fulldelim = "%" .. delim
- else
- fulldelim = delim
- end
- print("fulldelim: ", fulldelim)
- str = str .. delim
- for w in str:gmatch("(.-)" .. fulldelim) do
- items[#items + 1] = w
- end
- return items
+ local items = {}
+ local fulldelim = nil
+ if delim == "." or delim == "-" then
+ fulldelim = "%" .. delim
+ else
+ fulldelim = delim
+ end
+ str = str .. delim
+ for w in str:gmatch("(.-)" .. fulldelim) do
+ items[#items + 1] = w
+ end
+ return items
+end
+
+--- Escape a string to use as a lua pattern
+function M.escape(str)
+ return str:gsub("(%W)", "%%%1")
end
return M