Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic template insertion in daily notes #195

Merged
merged 5 commits into from
Sep 21, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added config option `sort_by` to allow setting search result order by "path", "modified", "accessed", or "created".
- Added config option `sort_reversed` to allow setting search result sort reversed order. The default is `true`.
- Added an extra option for daily notes to allow changing the default title from "%B %-d, %Y" to other strings.
- Added a configuration option `daily_notes.template` for automatically using a specific template when creating a new daily note.
- Adding a configuration option `templates.substitutions` for defining custom template substitutions.

### Changed

Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ This is a complete list of all of the options that can be passed to `require("ob
date_format = "%Y-%m-%d",
-- Optional, if you want to change the date format of the default alias of daily notes.
alias_format = "%B %-d, %Y"
-- Optional, if you want to automatically insert a template from your template directory like 'daily.md'
template = nil
},

-- Optional, completion.
Expand Down Expand Up @@ -213,6 +215,8 @@ This is a complete list of all of the options that can be passed to `require("ob
subdir = "templates",
date_format = "%Y-%m-%d-%a",
time_format = "%H:%M",
-- A map for custom variables, the key should be the variable and the value a function
substitutions = {}
},

-- Optional, customize the backlinks interface.
Expand Down Expand Up @@ -328,7 +332,7 @@ For example, with the following configuration
templates = {
subdir = "my-templates-folder",
date_format = "%Y-%m-%d-%a",
time_format = "%H:%M"
time_format = "%H:%M",
},
}
```
Expand All @@ -351,6 +355,20 @@ Date created: 2023-03-01-Wed

above the cursor position.

You can also define custom template substitutions with the configuration field `templates.substitutions`. For example, to automatically substitute the template variable `{{yesterday}}` when inserting a template, you could add this to your config:

```lua
{
-- other fields ...
templates = {
substitutions = {
yesterday = function()
return os.date("%Y-%m-%d", os.time() - 86400)
end
}
}
```

## Known Issues

### Configuring vault directory behind a link
Expand Down
1 change: 1 addition & 0 deletions lua/obsidian/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ end
---@field folder string|?
---@field date_format string|?
---@field alias_format string|?
---@field template string|?
config.DailyNotesOpts = {}

---Get defaults.
Expand Down
3 changes: 3 additions & 0 deletions lua/obsidian/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ client._daily = function(self, datetime)
-- Create Note object and save if it doesn't already exist.
local note = obsidian.note.new(id, { alias }, { "daily-notes" }, path)
if not note:exists() then
if self.opts.daily_notes.template then
obsidian.util.clone_template(self.opts.daily_notes.template, tostring(path), self, note:display_name())
end
local frontmatter = nil
if self.opts.note_frontmatter_func ~= nil then
frontmatter = self.opts.note_frontmatter_func(note)
Expand Down
63 changes: 56 additions & 7 deletions lua/obsidian/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,61 @@ util.get_active_window_cursor_location = function()
return location
end

---Substitute Variables inside a given Text
---
---@param text string - name of a template in the configured templates folder
---@param client obsidian.Client
---@param title string|nil
---@return string
util.substitute_template_variables = function(text, client, title)
local methods = client.opts.templates.substitutions or {}
if not methods["date"] then
methods["date"] = function()
local date_format = client.opts.templates.date_format or "%Y-%m-%d"
return tostring(os.date(date_format))
end
end
if not methods["time"] then
methods["time"] = function()
local time_format = client.opts.templates.time_format or "%Y-%m-%d"
return tostring(os.date(time_format))
end
end
if title then
methods["title"] = function()
return title
end
end
for key, value in pairs(methods) do
text = string.gsub(text, "{{" .. key .. "}}", value())
end
return text
end

---Clone Template
---
---@param template_name string - name of a template in the configured templates folder
---@param note_path string
---@param client obsidian.Client
---@param title string
util.clone_template = function(template_name, note_path, client, title)
local template_path = Path:new(client.templates_dir) / template_name
local template_file = io.open(tostring(template_path), "r")
local note_file = io.open(tostring(note_path), "wb")
if not template_file then
return error("Unable to read template at " .. template_path)
end
if not note_file then
return error("Unable to write note at " .. note_path)
end
for line in template_file:lines "L" do
line = util.substitute_template_variables(line, client, title)
note_file:write(line)
end
template_file:close()
note_file:close()
end

---Insert a template at the given location.
---
---@param name string - name of a template in the configured templates folder
Expand All @@ -451,20 +506,14 @@ end
util.insert_template = function(name, client, location)
local buf, win, row, col = unpack(location)
local template_path = Path:new(client.templates_dir) / name
local date_format = client.opts.templates.date_format or "%Y-%m-%d"
local time_format = client.opts.templates.time_format or "%H:%M"
local date = tostring(os.date(date_format))
local time = tostring(os.date(time_format))
local title = require("obsidian.note").from_buffer(buf, client.dir):display_name()

local insert_lines = {}
local template_file = io.open(tostring(template_path), "r")
if template_file then
local lines = template_file:lines()
for line in lines do
line = string.gsub(line, "{{date}}", date)
line = string.gsub(line, "{{time}}", time)
line = string.gsub(line, "{{title}}", title)
line = util.substitute_template_variables(line, client, title)
table.insert(insert_lines, line)
end
template_file:close()
Expand Down