From 4e43db217c47341efe59689ffaad131c7282cd44 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 14 Sep 2024 19:57:58 +0500 Subject: [PATCH 1/4] Add merge_frontmatter to merge frontmatter of template and buffer --- lua/obsidian/templates.lua | 93 ++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 15 deletions(-) diff --git a/lua/obsidian/templates.lua b/lua/obsidian/templates.lua index ac8a83f27..1135a82d3 100644 --- a/lua/obsidian/templates.lua +++ b/lua/obsidian/templates.lua @@ -1,7 +1,8 @@ local Path = require "obsidian.path" local Note = require "obsidian.note" local util = require "obsidian.util" - +local iter = require("obsidian.itertools").iter +local compat = require "obsidian.compat" local M = {} --- Resolve a template name to a path. @@ -149,6 +150,64 @@ M.clone_template = function(opts) return new_note end +--- Merges frontmatter of buffer and passed line iterator e.g Template +---@param line_iterator fun(): string? +---@param note obisidan.Note -- Note created from buffer to merge into +---@param buf integer -- Id of buffer to merge into +---@param opts { template_name: string|obsidian.Path, client: obsidian.Client, location: { [1]: integer, [2]: integer, [3]: integer, [4]: integer } } Options. +--- + +local merge_frontmatter = function(line_iterator, note, buf, opts) + local frontmatter = {} + frontmatter[1] = "---" + for line in line_iterator do + if line == "---" then + break + end + local new_line = M.substitute_template_variables(line, opts.client, note) + frontmatter[#frontmatter + 1] = new_line + end + frontmatter[#frontmatter + 1] = "---" + local template_as_note = Note.from_lines(iter(frontmatter), note.path, opts) + note:frontmatter_lines() + if note.metadata == null then + note.metadata = {} + end + for key in iter(template_as_note.metadata) do + note.metadata[key] = template_as_note[key] + end + for key in iter(template_as_note.tags) do + note:add_tag(key) + end + local insert_lines = compat.flatten(note:frontmatter_lines(false)) + local end_row = 0 + local buffer_lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) + local has_frontmatter, first_line = false, true + local line_index = 0 + for line in iter(buffer_lines) do + if first_line then + first_line = false + if line ~= "---" then + has_frontmatter = false + break + end + line_index = line_index + 1 + if line == "---" then + has_frontmatter = true + end_row = line_index + break + end + end + end + if has_frontmatter then + vim.api.nvim_buf_set_lines(buf, 0, end_row, false,{}) + end + if has_frontmatter == false and line_index > 1 then + vim.api.nvim_buf_set_lines(buf,0,0,false,{}) + end + vim.api.nvim_buf_set_lines(buf,0,0,false,insert_lines) +end + ---Insert a template at the given location. --- ---@param opts { template_name: string|obsidian.Path, client: obsidian.Client, location: { [1]: integer, [2]: integer, [3]: integer, [4]: integer } } Options. @@ -157,28 +216,32 @@ end M.insert_template = function(opts) local buf, win, row, _ = unpack(opts.location) local note = Note.from_buffer(buf) - local template_path = resolve_template(opts.template_name, opts.client) local insert_lines = {} local template_file = io.open(tostring(template_path), "r") if template_file then local lines = template_file:lines() + local line_number = 1 for line in lines do - local new_lines = M.substitute_template_variables(line, opts.client, note) - if string.find(new_lines, "[\r\n]") then - local line_start = 1 - for line_end in util.gfind(new_lines, "[\r\n]") do - local new_line = string.sub(new_lines, line_start, line_end - 1) - table.insert(insert_lines, new_line) - line_start = line_end + 1 - end - local last_line = string.sub(new_lines, line_start) - if string.len(last_line) > 0 then - table.insert(insert_lines, last_line) - end + if line_number == 1 and line == "---" then + merge_frontmatter(lines, note, buf, opts) else - table.insert(insert_lines, new_lines) + local new_lines = M.substitute_template_variables(line, opts.client, note) + if string.find(new_lines, "[\r\n]") then + local line_start = 1 + for line_end in util.gfind(new_lines, "[\r\n]") do + local new_line = string.sub(new_lines, line_start, line_end - 1) + table.insert(insert_lines, new_line) + line_start = line_end + 1 + end + local last_line = string.sub(new_lines, line_start) + if string.len(last_line) > 0 then + table.insert(insert_lines, last_line) + end + else + table.insert(insert_lines, new_lines) + end end end template_file:close() From bec580f7ae3b7b31e8a7bc964c40307f51f0e732 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 14 Sep 2024 20:07:01 +0500 Subject: [PATCH 2/4] Fix null check --- CHANGELOG.md | 1 + lua/obsidian/templates.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b585ed0e2..b772e68cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an edge case with collecting backlinks. - Fixed typo in `ObsidianPasteImg`'s command description - Fixed the case when `opts.attachments` is `nil`. +- Fixed frontmatter not updating when inserting template ## [v3.9.0](https://github.com/epwalsh/obsidian.nvim/releases/tag/v3.9.0) - 2024-07-11 diff --git a/lua/obsidian/templates.lua b/lua/obsidian/templates.lua index 1135a82d3..3578478e1 100644 --- a/lua/obsidian/templates.lua +++ b/lua/obsidian/templates.lua @@ -170,7 +170,7 @@ local merge_frontmatter = function(line_iterator, note, buf, opts) frontmatter[#frontmatter + 1] = "---" local template_as_note = Note.from_lines(iter(frontmatter), note.path, opts) note:frontmatter_lines() - if note.metadata == null then + if not note.metadata then note.metadata = {} end for key in iter(template_as_note.metadata) do From 4eb4bf105853f27efa646a5ef9a5459d0516459a Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 14 Sep 2024 23:24:30 +0500 Subject: [PATCH 3/4] Change implementation to cater for corner-cases --- lua/obsidian/templates.lua | 103 +++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/lua/obsidian/templates.lua b/lua/obsidian/templates.lua index 3578478e1..2f47c7e62 100644 --- a/lua/obsidian/templates.lua +++ b/lua/obsidian/templates.lua @@ -150,26 +150,44 @@ M.clone_template = function(opts) return new_note end ---- Merges frontmatter of buffer and passed line iterator e.g Template +--- Reads line from line_iterator and appends the frontmatter to the passed note +--- Returns remaining content of the line_iterator and the size of frontmatter ---@param line_iterator fun(): string? ----@param note obisidan.Note -- Note created from buffer to merge into ----@param buf integer -- Id of buffer to merge into +---@param note obisidan.Note -- Note created from buffer +---@param buf integer -- buffer id of the opened buffer ---@param opts { template_name: string|obsidian.Path, client: obsidian.Client, location: { [1]: integer, [2]: integer, [3]: integer, [4]: integer } } Options. +---@return integer -- Total lines of frontmatter +---@return table -- Remaining content of passed iterator excluding frontmatter --- local merge_frontmatter = function(line_iterator, note, buf, opts) - local frontmatter = {} - frontmatter[1] = "---" + local data = {} + local frontmatter_end = 0 + local content_start + local in_frontmatter, has_frontmatter, first_line = false, false, true for line in line_iterator do if line == "---" then - break + if first_line then + first_line = false + in_frontmatter = true + else + has_frontmatter = true + in_frontmatter = false + frontmatter_end = frontmatter_end + 1 + end end local new_line = M.substitute_template_variables(line, opts.client, note) - frontmatter[#frontmatter + 1] = new_line + data[#data + 1] = new_line + if in_frontmatter then + frontmatter_end = frontmatter_end + 1 + elseif content_start == nil then + content_start = frontmatter_end + 1 + end end - frontmatter[#frontmatter + 1] = "---" - local template_as_note = Note.from_lines(iter(frontmatter), note.path, opts) - note:frontmatter_lines() + if has_frontmatter == false and frontmatter_end > 0 then + error "Template has invalid frontmatter!" + end + local template_as_note = Note.from_lines(iter { unpack(data, 1, frontmatter_end) }, note.path, opts) if not note.metadata then note.metadata = {} end @@ -180,32 +198,11 @@ local merge_frontmatter = function(line_iterator, note, buf, opts) note:add_tag(key) end local insert_lines = compat.flatten(note:frontmatter_lines(false)) - local end_row = 0 - local buffer_lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) - local has_frontmatter, first_line = false, true - local line_index = 0 - for line in iter(buffer_lines) do - if first_line then - first_line = false - if line ~= "---" then - has_frontmatter = false - break - end - line_index = line_index + 1 - if line == "---" then - has_frontmatter = true - end_row = line_index - break - end - end - end if has_frontmatter then - vim.api.nvim_buf_set_lines(buf, 0, end_row, false,{}) + vim.api.nvim_buf_set_lines(buf, 0, frontmatter_end, false, {}) end - if has_frontmatter == false and line_index > 1 then - vim.api.nvim_buf_set_lines(buf,0,0,false,{}) - end - vim.api.nvim_buf_set_lines(buf,0,0,false,insert_lines) + vim.api.nvim_buf_set_lines(buf, 0, 0, false, insert_lines) + return content_start, { unpack(data, content_start, #data) } end ---Insert a template at the given location. @@ -217,39 +214,33 @@ M.insert_template = function(opts) local buf, win, row, _ = unpack(opts.location) local note = Note.from_buffer(buf) local template_path = resolve_template(opts.template_name, opts.client) - local insert_lines = {} local template_file = io.open(tostring(template_path), "r") if template_file then local lines = template_file:lines() - local line_number = 1 - for line in lines do - if line_number == 1 and line == "---" then - merge_frontmatter(lines, note, buf, opts) - else - local new_lines = M.substitute_template_variables(line, opts.client, note) - if string.find(new_lines, "[\r\n]") then - local line_start = 1 - for line_end in util.gfind(new_lines, "[\r\n]") do - local new_line = string.sub(new_lines, line_start, line_end - 1) - table.insert(insert_lines, new_line) - line_start = line_end + 1 - end - local last_line = string.sub(new_lines, line_start) - if string.len(last_line) > 0 then - table.insert(insert_lines, last_line) - end - else - table.insert(insert_lines, new_lines) + local content_start, data = merge_frontmatter(lines, note, buf,opts) + row = content_start + for line in iter(data) do + if string.find(line, "[\r\n]") then + local line_start = 1 + for line_end in util.gfind(line, "[\r\n]") do + local new_line = string.sub(line, line_start, line_end - 1) + table.insert(insert_lines, new_line) + line_start = line_end + 1 + end + local last_line = string.sub(line, line_start) + if string.len(last_line) > 0 then + table.insert(insert_lines, last_line) end + else + table.insert(insert_lines, line) end end template_file:close() else error(string.format("Template file '%s' not found", template_path)) end - - vim.api.nvim_buf_set_lines(buf, row - 1, row - 1, false, insert_lines) + vim.api.nvim_buf_set_lines(buf, row, row, false, insert_lines) local new_cursor_row, _ = unpack(vim.api.nvim_win_get_cursor(win)) vim.api.nvim_win_set_cursor(0, { new_cursor_row, 0 }) From 00393c26eb4ca1cab11caeb46a7b6823cd31575e Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sat, 14 Sep 2024 23:55:57 +0500 Subject: [PATCH 4/4] Fix: checks disable_frontmatter now --- lua/obsidian/templates.lua | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/lua/obsidian/templates.lua b/lua/obsidian/templates.lua index 2f47c7e62..7de2f86c7 100644 --- a/lua/obsidian/templates.lua +++ b/lua/obsidian/templates.lua @@ -153,16 +153,17 @@ end --- Reads line from line_iterator and appends the frontmatter to the passed note --- Returns remaining content of the line_iterator and the size of frontmatter ---@param line_iterator fun(): string? ----@param note obisidan.Note -- Note created from buffer ---@param buf integer -- buffer id of the opened buffer ---@param opts { template_name: string|obsidian.Path, client: obsidian.Client, location: { [1]: integer, [2]: integer, [3]: integer, [4]: integer } } Options. ---@return integer -- Total lines of frontmatter ---@return table -- Remaining content of passed iterator excluding frontmatter --- -local merge_frontmatter = function(line_iterator, note, buf, opts) +local merge_frontmatter = function(line_iterator, buf, opts) local data = {} + local note = Note.from_buffer(buf) local frontmatter_end = 0 + local manage_frontmatter = opts.client:should_save_frontmatter(note) local content_start local in_frontmatter, has_frontmatter, first_line = false, false, true for line in line_iterator do @@ -184,25 +185,29 @@ local merge_frontmatter = function(line_iterator, note, buf, opts) content_start = frontmatter_end + 1 end end - if has_frontmatter == false and frontmatter_end > 0 then - error "Template has invalid frontmatter!" - end - local template_as_note = Note.from_lines(iter { unpack(data, 1, frontmatter_end) }, note.path, opts) - if not note.metadata then - note.metadata = {} - end - for key in iter(template_as_note.metadata) do - note.metadata[key] = template_as_note[key] - end - for key in iter(template_as_note.tags) do - note:add_tag(key) - end - local insert_lines = compat.flatten(note:frontmatter_lines(false)) - if has_frontmatter then - vim.api.nvim_buf_set_lines(buf, 0, frontmatter_end, false, {}) + if manage_frontmatter then + if has_frontmatter == false and frontmatter_end > 0 then + error "Template has invalid frontmatter!" + end + local template_as_note = Note.from_lines(iter { unpack(data, 1, frontmatter_end) }, note.path, opts) + if not note.metadata then + note.metadata = {} + end + for key in iter(template_as_note.metadata) do + note.metadata[key] = template_as_note[key] + end + for key in iter(template_as_note.tags) do + note:add_tag(key) + end + local insert_lines = compat.flatten(note:frontmatter_lines(false)) + if has_frontmatter then + vim.api.nvim_buf_set_lines(buf, 0, frontmatter_end, false, {}) + end + vim.api.nvim_buf_set_lines(buf, 0, 0, false, insert_lines) + return content_start, { unpack(data, content_start, #data) } + else + return nil, data end - vim.api.nvim_buf_set_lines(buf, 0, 0, false, insert_lines) - return content_start, { unpack(data, content_start, #data) } end ---Insert a template at the given location. @@ -212,14 +217,13 @@ end ---@return obsidian.Note M.insert_template = function(opts) local buf, win, row, _ = unpack(opts.location) - local note = Note.from_buffer(buf) local template_path = resolve_template(opts.template_name, opts.client) local insert_lines = {} local template_file = io.open(tostring(template_path), "r") if template_file then local lines = template_file:lines() - local content_start, data = merge_frontmatter(lines, note, buf,opts) - row = content_start + local content_start, data = merge_frontmatter(lines, buf, opts) + row = content_start or row - 1 for line in iter(data) do if string.find(line, "[\r\n]") then local line_start = 1