Skip to content
Open
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
84 changes: 78 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ That's it! You're ready to start building your knowledge base.

### Core Features
- **📅 Daily Notes** - Quick creation and navigation with automatic templating
- **📆 Weekly Notes** - ISO week-based notes for weekly reviews and planning
- **📝 Template System** - Flexible templates with variable substitution (`{{date}}`, `{{time}}`, `{{title}}`, etc.)
- **🔗 Wiki-style Links** - Create and follow `[[note-name]]` links between notes
- **🔄 Smart Renaming** - Rename notes and automatically update all references with file preview
Expand Down Expand Up @@ -116,6 +117,7 @@ require("markdown-notes").setup({
vault_path = "~/notes", -- Where your notes live
templates_path = "~/notes/templates", -- Where your templates live
dailies_path = "~/notes/daily", -- Where daily notes go
weekly_path = "~/notes/weekly", -- Where weekly notes go
})
```

Expand All @@ -128,6 +130,9 @@ All keybindings use `<leader>n` as the prefix for easy discovery:
| `<leader>nd` | Daily note (today) | Create/open today's daily note |
| `<leader>ny` | Daily note (yesterday) | Open yesterday's daily note |
| `<leader>nt` | Daily note (tomorrow) | Open tomorrow's daily note |
| `<leader>nww` | Weekly note (this week) | Create/open this week's weekly note |
| `<leader>nwl` | Weekly note (last week) | Open last week's weekly note |
| `<leader>nwn` | Weekly note (next week) | Open next week's weekly note |
| `<leader>nn` | New note | Create a new note |
| `<leader>nc` | New note from template | Create note with template selection |
| `<leader>nf` | Find notes | Search and open existing notes |
Expand All @@ -137,7 +142,7 @@ All keybindings use `<leader>n` as the prefix for easy discovery:
| `<leader>ng` | Search tags | Find notes by frontmatter tags |
| `<leader>nb` | Show backlinks | Show notes linking to current note |
| `<leader>nr` | Rename note | Rename note and update all references with preview |
| `<leader>nw` | Pick workspace | Switch between workspaces |
| `<leader>nW` | Pick workspace | Switch between workspaces (capital W) |
| `gf` | Follow link | Follow link under cursor |

> **💡 Tip:** All keybindings can be customized in your configuration.
Expand All @@ -154,6 +159,25 @@ Daily notes are the heart of many note-taking workflows. Start your day by creat

If you have a `Daily.md` template, it will be automatically applied. Otherwise, a basic note with frontmatter is created.

### Weekly Notes and Reviews

Weekly notes help you plan and review your week at a higher level. They use ISO week numbers for consistency:

```
<leader>nww → Creates/opens this week's note (e.g., W03-2025-Weekly-Review.md)
<leader>nwl → Opens last week's note
<leader>nwn → Opens next week's note
```

Weekly notes are created with the format `W{week}-{year}-Weekly-Review.md` and automatically apply your `Weekly.md` template if available. The plugin uses ISO week numbers where:
- Weeks start on Monday
- Week 1 is the week containing the first Thursday of the year

**Example workflow:**
1. Start each week with `<leader>nww` to create your weekly planning note
2. Review last week with `<leader>nwl` before planning the current week
3. Use template variables like `{{week_number}}`, `{{week_year}}`, and `{{week_id}}` in your Weekly template

### Creating and Managing Notes

#### Basic Note Creation
Expand Down Expand Up @@ -226,6 +250,8 @@ tags: [meetings]

| Command | Description |
|---------|-------------|
| `:MarkdownNotesDailyOpen [offset]` | Open daily note (offset in days from today) |
| `:MarkdownNotesWeeklyOpen [offset]` | Open weekly note (offset in weeks from this week) |
| `:MarkdownNotesRename [name]` | Rename current note and update references |
| `:MarkdownNotesWorkspaceStatus` | Show current workspace |
| `:MarkdownNotesWorkspacePick` | Switch workspace with fuzzy finder |
Expand Down Expand Up @@ -254,12 +280,22 @@ require("markdown-notes").setup({

-- Custom template variables
template_vars = {
-- Date/time variables
date = function() return os.date("%Y-%m-%d") end,
time = function() return os.date("%H:%M") end,
datetime = function() return os.date("%Y-%m-%d %H:%M") end,
title = function() return vim.fn.expand("%:t:r") end,
yesterday = function() return os.date("%Y-%m-%d", os.time() - 86400) end,
tomorrow = function() return os.date("%Y-%m-%d", os.time() + 86400) end,
-- Week variables
week_number = function() return os.date("%U") end,
week_year = function() return os.date("%Y") end,
week_id = function() return "W" .. os.date("%U") .. "-" .. os.date("%Y") end,
-- Full date format variables
full_date = function() return os.date("%A, %B %d, %Y") end,
year = function() return os.date("%Y") end,
month = function() return os.date("%B") end,
day_name = function() return os.date("%A") end,
-- Add your own custom variables
author = function() return "Your Name" end,
project = function() return vim.fn.getcwd():match("([^/]+)$") end,
Expand All @@ -268,8 +304,11 @@ require("markdown-notes").setup({
-- Customize keybindings
mappings = {
daily_note_today = "<leader>nd",
daily_note_yesterday = "<leader>ny",
daily_note_yesterday = "<leader>ny",
daily_note_tomorrow = "<leader>nt",
weekly_note_this_week = "<leader>nww",
weekly_note_last_week = "<leader>nwl",
weekly_note_next_week = "<leader>nwn",
new_note = "<leader>nn",
new_note_from_template = "<leader>nc",
find_notes = "<leader>nf",
Expand All @@ -280,6 +319,7 @@ require("markdown-notes").setup({
show_backlinks = "<leader>nb",
follow_link = "gf",
rename_note = "<leader>nr",
pick_workspace = "<leader>nW",
},
})
```
Expand Down Expand Up @@ -321,7 +361,7 @@ require("markdown-notes").setup_workspace("research", {

#### Workspace Workflow

- **Switch workspaces**: Use `<leader>nw` to pick from available workspaces
- **Switch workspaces**: Use `<leader>nW` (capital W) to pick from available workspaces
- **Persistent context**: All commands use the active workspace until you switch
- **Independent settings**: Each workspace has its own paths, templates, and variables

Expand Down Expand Up @@ -355,6 +395,13 @@ Templates are markdown files with special `{{variable}}` syntax that gets substi
| `{{title}}` | File name without extension | `meeting-notes` |
| `{{yesterday}}` | Yesterday's date | `2025-01-14` |
| `{{tomorrow}}` | Tomorrow's date | `2025-01-16` |
| `{{week_number}}` | ISO week number | `03` |
| `{{week_year}}` | Year for the week | `2025` |
| `{{week_id}}` | Week identifier | `W03-2025` |
| `{{full_date}}` | Full date format | `Wednesday, January 15, 2025` |
| `{{year}}` | Current year | `2025` |
| `{{month}}` | Current month name | `January` |
| `{{day_name}}` | Current day name | `Wednesday` |

### Creating Custom Variables

Expand Down Expand Up @@ -392,6 +439,31 @@ tags: [daily]
- [ ]
```

**Weekly Note Template** (`templates/Weekly.md`):
```markdown
---
title: Week {{week_number}} - {{week_year}}
date: {{date}}
week: {{week_id}}
tags: [weekly, review]
---

# Week {{week_number}}, {{week_year}}

## 📊 Week Overview

**Week of:** {{full_date}}

## 🎯 Goals for This Week
- [ ]

## 📝 Weekly Accomplishments

## 🔄 Next Week's Focus

## 📚 Notes and Learnings
```

**Meeting Template** (`templates/meeting.md`):
```markdown
---
Expand All @@ -403,15 +475,15 @@ attendees: []

# {{title}}

**Date:** {{datetime}}
**Attendees:**
**Date:** {{datetime}}
**Attendees:**

## 📋 Agenda

## 📝 Discussion Notes

## ✅ Action Items
- [ ]
- [ ]

## 🔗 Links
```
Expand Down
4 changes: 2 additions & 2 deletions doc/markdown-notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ Templates and Tags~
`<leader>ng` Find notes by frontmatter tags

Workspaces~
`<leader>nw` Switch between workspaces
`<leader>nW` Pick workspace

Note: All keybindings can be customized in your configuration.

Expand Down Expand Up @@ -339,7 +339,7 @@ Setting Up Workspaces~

Workspace Workflow~
*markdown-notes-workspace-workflow*
- Switch workspaces: Use `<leader>nw` to pick from available workspaces
- Switch workspaces: Use `<leader>nW` to pick from available workspaces
- Persistent context: All commands use the active workspace until you switch
- Independent settings: Each workspace has its own paths, templates, and variables

Expand Down
28 changes: 27 additions & 1 deletion lua/markdown-notes/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ M.defaults = {
tomorrow = function()
return os.date("%Y-%m-%d", os.time() + 86400)
end,
-- Week-related variables
week_number = function()
return os.date("%U")
end,
week_year = function()
return os.date("%Y")
end,
week_id = function()
return "W" .. os.date("%U") .. "-" .. os.date("%Y")
end,
-- Full date format variables
full_date = function()
return os.date("%A, %B %d, %Y")
end,
year = function()
return os.date("%Y")
end,
month = function()
return os.date("%B")
end,
day_name = function()
return os.date("%A")
end,
},

-- Default workspace (optional)
Expand All @@ -44,6 +67,9 @@ M.defaults = {
daily_note_today = "<leader>nd",
daily_note_yesterday = "<leader>ny",
daily_note_tomorrow = "<leader>nt",
weekly_note_this_week = "<leader>nww",
weekly_note_last_week = "<leader>nwl",
weekly_note_next_week = "<leader>nwn",
new_note = "<leader>nn",
new_note_from_template = "<leader>nc",
find_notes = "<leader>nf",
Expand All @@ -54,7 +80,7 @@ M.defaults = {
show_backlinks = "<leader>nb",
follow_link = "gf",
rename_note = "<leader>nr",
pick_workspace = "<leader>nw",
pick_workspace = "<leader>nW",
},
}

Expand Down
30 changes: 30 additions & 0 deletions lua/markdown-notes/init.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local config = require("markdown-notes.config")
local templates = require("markdown-notes.templates")
local daily = require("markdown-notes.daily")
local weekly = require("markdown-notes.weekly")
local notes = require("markdown-notes.notes")
local links = require("markdown-notes.links")
local workspace = require("markdown-notes.workspace")
Expand Down Expand Up @@ -58,6 +59,17 @@ function M.setup_keymaps()
daily.open_daily_note(1)
end, "Open tomorrow's note")

-- Weekly notes
map("n", "weekly_note_this_week", function()
weekly.open_weekly_note(0)
end, "Open this week's note")
map("n", "weekly_note_last_week", function()
weekly.open_weekly_note(-1)
end, "Open last week's note")
map("n", "weekly_note_next_week", function()
weekly.open_weekly_note(1)
end, "Open next week's note")

-- Note management
map("n", "new_note", notes.create_new_note, "Create new note")
map("n", "new_note_from_template", notes.create_from_template, "Create new note from template")
Expand Down Expand Up @@ -85,6 +97,24 @@ function M.setup_keymaps()
-- Workspaces
map("n", "pick_workspace", workspace.pick_workspace, "Pick workspace")

-- Daily note commands
vim.api.nvim_create_user_command("MarkdownNotesDailyOpen", function(opts)
local offset = 0
if opts.args and opts.args ~= "" then
offset = tonumber(opts.args) or 0
end
daily.open_daily_note(offset)
end, { nargs = "?", desc = "Open daily note (offset in days from today)" })

-- Weekly note commands
vim.api.nvim_create_user_command("MarkdownNotesWeeklyOpen", function(opts)
local offset = 0
if opts.args and opts.args ~= "" then
offset = tonumber(opts.args) or 0
end
weekly.open_weekly_note(offset)
end, { nargs = "?", desc = "Open weekly note (offset in weeks from this week)" })

-- Note management commands
vim.api.nvim_create_user_command("MarkdownNotesRename", function(opts)
if opts.args and opts.args ~= "" then
Expand Down
69 changes: 69 additions & 0 deletions lua/markdown-notes/weekly.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
local config = require("markdown-notes.config")
local templates = require("markdown-notes.templates")

local M = {}

-- Calculate ISO week number and year for a given timestamp
-- ISO weeks start on Monday and the first week of the year is the one containing the first Thursday
local function get_iso_week(timestamp)
timestamp = timestamp or os.time()
local date = os.date("*t", timestamp)

-- Get day of week (1=Monday, 7=Sunday)
local dow = (date.wday + 5) % 7 + 1

-- Find Thursday of the current week
local thursday = timestamp + (4 - dow) * 86400
local thursday_date = os.date("*t", thursday)

-- Get January 4th of the same year (always in week 1)
local jan4 = os.time({year = thursday_date.year, month = 1, day = 4, hour = 12})
local jan4_date = os.date("*t", jan4)
local jan4_dow = (jan4_date.wday + 5) % 7 + 1

-- Find Monday of week 1
local week1_monday = jan4 - (jan4_dow - 1) * 86400

-- Calculate week number
local week = math.floor((thursday - week1_monday) / (7 * 86400)) + 1

return week, thursday_date.year
end

function M.open_weekly_note(offset)
offset = offset or 0
local timestamp = os.time() + (offset * 7 * 86400) -- offset in weeks
local week, year = get_iso_week(timestamp)

local options = config.get_current_config()
local filename = string.format("W%02d-%d-Weekly-Review.md", week, year)
local file_path = vim.fn.expand(options.weekly_path .. "/" .. filename)

-- Create directory if it doesn't exist
local dir = vim.fn.fnamemodify(file_path, ":h")
if vim.fn.isdirectory(dir) == 0 then
vim.fn.mkdir(dir, "p")
end

-- Create file with template if it doesn't exist
if vim.fn.filereadable(file_path) == 0 then
local template_path = vim.fn.expand(options.templates_path .. "/Weekly.md")
if vim.fn.filereadable(template_path) == 1 then
local template_content = vim.fn.readfile(template_path)
local custom_vars = {
week_number = string.format("%02d", week),
week_year = tostring(year),
week_id = string.format("W%02d-%d", week, year),
title = string.format("Week %d, %d", week, year),
date = os.date("%Y-%m-%d", timestamp),
datetime = os.date("%Y-%m-%d %H:%M", timestamp),
}
template_content = templates.substitute_template_vars(template_content, custom_vars)
vim.fn.writefile(template_content, file_path)
end
end

vim.cmd("edit " .. file_path)
end

return M
20 changes: 20 additions & 0 deletions tests/markdown-notes/weekly_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
local weekly = require("markdown-notes.weekly")
local config = require("markdown-notes.config")

describe("weekly", function()
before_each(function()
config.options = {}
config.workspaces = {}
config.setup({
weekly_path = "/tmp/test-weekly-notes",
templates_path = "/tmp/test-templates",
})
end)

describe("open_weekly_note", function()
it("creates weekly note with ISO week format", function()
-- This is a basic test to verify the module loads and function exists
assert.is_function(weekly.open_weekly_note)
end)
end)
end)