Skip to content

Commit

Permalink
Merge branch 'main' into feat-allow-grouping-notes-by-date
Browse files Browse the repository at this point in the history
  • Loading branch information
alpham authored Dec 14, 2024
2 parents 9607498 + 14e0427 commit 156c7cb
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 32 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Added `opts.follow_img_func` option for customizing how to handle image paths.
- Added better handling for undefined template fields, which will now be prompted for.

### Changed

- Renamed `opts.image_name_func` to `opts.attachments.img_name_func`.

### Fixed

- Fixed an edge case with collecting backlinks.
- Fixed typo in `ObsidianPasteImg`'s command description
- Fixed the case when `opts.attachments` is `nil`.

## [v3.9.0](https://github.com/epwalsh/obsidian.nvim/releases/tag/v3.9.0) - 2024-07-11

### Added
Expand Down
45 changes: 32 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ _Keep in mind this plugin is not meant to replace Obsidian, but to complement it

- `:ObsidianToggleCheckbox` to cycle through checkbox options.

- `:ObsidianNewFromTemplate [PATH] [TEMPLATE]` to create a new note from a template in the templates folder. Selecting from a list using your preferred picker.
This command has one optional argument: the path to the new note.
- `:ObsidianNewFromTemplate [TITLE]` to create a new note from a template in the templates folder. Selecting from a list using your preferred picker.
This command has one optional argument: the title of the new note.

- `:ObsidianTOC` to load the table of contents of the current note into a picker list.

Expand Down Expand Up @@ -129,9 +129,10 @@ return {
-- Replace the above line with this if you only want to load obsidian.nvim for markdown files in your vault:
-- event = {
-- -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'.
-- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/**.md"
-- "BufReadPre path/to/my-vault/**.md",
-- "BufNewFile path/to/my-vault/**.md",
-- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/*.md"
-- -- refer to `:h file-pattern` for more examples
-- "BufReadPre path/to/my-vault/*.md",
-- "BufNewFile path/to/my-vault/*.md",
-- },
dependencies = {
-- Required.
Expand Down Expand Up @@ -349,13 +350,6 @@ This is a complete list of all of the options that can be passed to `require("ob
-- Either 'wiki' or 'markdown'.
preferred_link_style = "wiki",

-- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`.
---@return string
image_name_func = function()
-- Prefix image names with timestamp.
return string.format("%s-", os.time())
end,

-- Optional, boolean or a function that takes a filename and returns a boolean.
-- `true` indicates that you don't want obsidian.nvim to manage frontmatter.
disable_frontmatter = false,
Expand Down Expand Up @@ -397,6 +391,17 @@ This is a complete list of all of the options that can be passed to `require("ob
-- Open the URL in the default web browser.
vim.fn.jobstart({"open", url}) -- Mac OS
-- vim.fn.jobstart({"xdg-open", url}) -- linux
-- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows
-- vim.ui.open(url) -- need Neovim 0.10.0+
end,

-- Optional, by default when you use `:ObsidianFollowLink` on a link to an image
-- file it will be ignored but you can customize this behavior here.
---@param img string
follow_img_func = function(img)
vim.fn.jobstart { "qlmanage", "-p", img } -- Mac OS quick look preview
-- vim.fn.jobstart({"xdg-open", url}) -- linux
-- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows
end,

-- Optional, set to true if you use the Obsidian Advanced URI plugin.
Expand All @@ -411,12 +416,18 @@ This is a complete list of all of the options that can be passed to `require("ob
name = "telescope.nvim",
-- Optional, configure key mappings for the picker. These are the defaults.
-- Not all pickers support all mappings.
mappings = {
note_mappings = {
-- Create a new note from your query.
new = "<C-x>",
-- Insert a link to the selected note.
insert_link = "<C-l>",
},
tag_mappings = {
-- Add tag(s) to current note.
tag_note = "<C-x>",
-- Insert a tag at the current location.
insert_tag = "<C-l>",
},
},

-- Optional, sort search results by "path", "modified", "accessed", or "created".
Expand Down Expand Up @@ -512,6 +523,14 @@ This is a complete list of all of the options that can be passed to `require("ob
-- If this is a relative path it will be interpreted as relative to the vault root.
-- You can always override this per image by passing a full path to the command instead of just a filename.
img_folder = "assets/imgs", -- This is the default

-- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`.
---@return string
img_name_func = function()
-- Prefix image names with timestamp.
return string.format("%s-", os.time())
end,

-- A function that determines the text to insert in the note when pasting an image.
-- It takes two arguments, the `obsidian.Client` and an `obsidian.Path` to the image file.
-- This is the default implementation.
Expand Down
47 changes: 33 additions & 14 deletions doc/obsidian.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ COMMANDS *obsidian-commands*
first by appending "–dry-run" to the command, e.g. `:ObsidianRename new-id
--dry-run`.
- `:ObsidianToggleCheckbox` to cycle through checkbox options.
- `:ObsidianNewFromTemplate [PATH] [TEMPLATE]` to create a new note from a
template in the templates folder. Selecting from a list using your preferred
picker. This command has one optional argument: the path to the new note.
- `:ObsidianNewFromTemplate [TITLE]` to create a new note from a template in the
templates folder. Selecting from a list using your preferred picker. This
command has one optional argument: the title of the new note.
- `:ObsidianTOC` to load the table of contents of the current note into a picker
list.

Expand Down Expand Up @@ -176,9 +176,10 @@ USING LAZY.NVIM ~
-- Replace the above line with this if you only want to load obsidian.nvim for markdown files in your vault:
-- event = {
-- -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'.
-- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/**.md"
-- "BufReadPre path/to/my-vault/**.md",
-- "BufNewFile path/to/my-vault/**.md",
-- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/*.md"
-- -- refer to `:h file-pattern` for more examples
-- "BufReadPre path/to/my-vault/*.md",
-- "BufNewFile path/to/my-vault/*.md",
-- },
dependencies = {
-- Required.
Expand Down Expand Up @@ -405,13 +406,6 @@ carefully and customize it to your needs:
-- Either 'wiki' or 'markdown'.
preferred_link_style = "wiki",

-- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`.
---@return string
image_name_func = function()
-- Prefix image names with timestamp.
return string.format("%s-", os.time())
end,

-- Optional, boolean or a function that takes a filename and returns a boolean.
-- `true` indicates that you don't want obsidian.nvim to manage frontmatter.
disable_frontmatter = false,
Expand Down Expand Up @@ -453,6 +447,17 @@ carefully and customize it to your needs:
-- Open the URL in the default web browser.
vim.fn.jobstart({"open", url}) -- Mac OS
-- vim.fn.jobstart({"xdg-open", url}) -- linux
-- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows
-- vim.ui.open(url) -- need Neovim 0.10.0+
end,

-- Optional, by default when you use `:ObsidianFollowLink` on a link to an image
-- file it will be ignored but you can customize this behavior here.
---@param img string
follow_img_func = function(img)
vim.fn.jobstart { "qlmanage", "-p", img } -- Mac OS quick look preview
-- vim.fn.jobstart({"xdg-open", url}) -- linux
-- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows
end,

-- Optional, set to true if you use the Obsidian Advanced URI plugin.
Expand All @@ -467,12 +472,18 @@ carefully and customize it to your needs:
name = "telescope.nvim",
-- Optional, configure key mappings for the picker. These are the defaults.
-- Not all pickers support all mappings.
mappings = {
note_mappings = {
-- Create a new note from your query.
new = "<C-x>",
-- Insert a link to the selected note.
insert_link = "<C-l>",
},
tag_mappings = {
-- Add tag(s) to current note.
tag_note = "<C-x>",
-- Insert a tag at the current location.
insert_tag = "<C-l>",
},
},

-- Optional, sort search results by "path", "modified", "accessed", or "created".
Expand Down Expand Up @@ -568,6 +579,14 @@ carefully and customize it to your needs:
-- If this is a relative path it will be interpreted as relative to the vault root.
-- You can always override this per image by passing a full path to the command instead of just a filename.
img_folder = "assets/imgs", -- This is the default

-- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`.
---@return string
img_name_func = function()
-- Prefix image names with timestamp.
return string.format("%s-", os.time())
end,

-- A function that determines the text to insert in the note when pasting an image.
-- It takes two arguments, the `obsidian.Client` and an `obsidian.Path` to the image file.
-- This is the default implementation.
Expand Down
12 changes: 11 additions & 1 deletion lua/obsidian/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,15 @@ Client.follow_link_async = function(self, link, opts)
return self:open_note(res.note, { line = res.line, col = res.col, open_strategy = opts.open_strategy })
end

if util.is_img(res.location) then
if self.opts.follow_img_func ~= nil then
self.opts.follow_img_func(res.location)
else
log.warn "This looks like an image path. You can customize the behavior of images with the 'follow_img_func' option."
end
return
end

if res.link_type == search.RefTypes.Wiki or res.link_type == search.RefTypes.WikiWithAlias then
-- Prompt to create a new note.
if util.confirm("Create new note '" .. res.location .. "'?") then
Expand Down Expand Up @@ -1308,7 +1317,8 @@ Client.find_backlinks_async = function(self, note, callback, opts)

-- Prepare search terms.
local search_terms = {}
for raw_ref in iter { tostring(note.id), note:fname(), self:vault_relative_path(note.path) } do
local note_path = Path.new(note.path)
for raw_ref in iter { tostring(note.id), note_path.name, note_path.stem, self:vault_relative_path(note.path) } do
for ref in
iter(util.tbl_unique {
raw_ref,
Expand Down
2 changes: 1 addition & 1 deletion lua/obsidian/commands/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ M.register(

M.register(
"ObsidianPasteImg",
{ opts = { nargs = "?", complete = "file", desc = "Paste and image from the clipboard" } }
{ opts = { nargs = "?", complete = "file", desc = "Paste an image from the clipboard" } }
)

M.register(
Expand Down
4 changes: 2 additions & 2 deletions lua/obsidian/commands/paste_img.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ return function(client, data)

---@type string|?
local default_name
if client.opts.image_name_func then
default_name = client.opts.image_name_func()
if client.opts.attachments.img_name_func then
default_name = client.opts.attachments.img_name_func()
end

local path = paste_img {
Expand Down
11 changes: 10 additions & 1 deletion lua/obsidian/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local config = {}
---@field markdown_link_func (fun(opts: {path: string, label: string, id: string|?}): string)
---@field preferred_link_style obsidian.config.LinkStyle
---@field follow_url_func fun(url: string)|?
---@field image_name_func (fun(): string)|?
---@field follow_img_func fun(img: string)|?
---@field note_frontmatter_func (fun(note: obsidian.Note): table)|?
---@field disable_frontmatter (fun(fname: string?): boolean)|boolean|?
---@field completion obsidian.config.CompletionOpts
Expand Down Expand Up @@ -207,6 +207,14 @@ config.ClientOpts.normalize = function(opts, defaults)
opts.templates.subdir = nil
end

if opts.image_name_func then
if opts.attachments == nil then
opts.attachments = {}
end
opts.attachments.img_name_func = opts.image_name_func
opts.image_name_func = nil
end

--------------------------
-- Merge with defaults. --
--------------------------
Expand Down Expand Up @@ -464,6 +472,7 @@ end
---@class obsidian.config.AttachmentsOpts
---
---@field img_folder string Default folder to save images to, relative to the vault root.
---@field img_name_func (fun(): string)|?
---@field img_text_func fun(client: obsidian.Client, path: obsidian.Path): string
---@field confirm_img_paste boolean Whether to confirm the paste or not. Defaults to true.
config.AttachmentsOpts = {}
Expand Down
10 changes: 10 additions & 0 deletions lua/obsidian/templates.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ M.substitute_template_variables = function(text, client, note)
methods["path"] = tostring(note.path)
end

-- Replace known variables.
for key, subst in pairs(methods) do
for m_start, m_end in util.gfind(text, "{{" .. key .. "}}", nil, true) do
---@type string
Expand All @@ -90,6 +91,15 @@ M.substitute_template_variables = function(text, client, note)
end
end

-- Find unknown variables and prompt for them.
for m_start, m_end in util.gfind(text, "{{[^}]+}}") do
local key = util.strip_whitespace(string.sub(text, m_start + 2, m_end - 2))
local value = util.input(string.format("Enter value for '%s' (<cr> to skip): ", key))
if value and string.len(value) > 0 then
text = string.sub(text, 1, m_start - 1) .. value .. string.sub(text, m_end + 1)
end
end

return text
end

Expand Down
9 changes: 9 additions & 0 deletions lua/obsidian/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ util.is_url = function(s)
end
end

util.is_img = function(s)
for _, suffix in ipairs { ".png", ".jpg", ".jpeg", ".heic", ".gif", ".svg", ".ico" } do
if vim.endswith(s, suffix) then
return true
end
end
return false
end

-- This function removes a single backslash within double square brackets
util.unescape_single_backslash = function(text)
return text:gsub("(%[%[[^\\]+)\\(%|[^\\]+]])", "%1%2")
Expand Down

0 comments on commit 156c7cb

Please sign in to comment.