Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6010880
feat(view): add support for viewing calendar file attachments
jugarpeupv Jan 19, 2026
3c83f8b
feat: add ability to supply email adress to Inbox command
antinomie8 Jan 10, 2026
d2b313a
fix: cannot compare tables in Inbox command
antinomie8 Jan 17, 2026
18e9a3e
style: apply consistent formatting to init.lua
yousefakbar Feb 1, 2026
0b1ab70
docs: document email address argument for Inbox command
yousefakbar Feb 1, 2026
bb6917b
refactor(thread): migrate to JSON parsing for thread display
yousefakbar Jan 14, 2026
b9fc182
feat(thread): add optional HTML body rendering via w3m
yousefakbar Jan 15, 2026
b9fc362
feat(thread): export thread metadata to buffer-local variable
yousefakbar Jan 16, 2026
b570007
feat(thread): add per-message metadata buffer variable
yousefakbar Jan 18, 2026
91c9379
feat(thread): add cursor-tracked current message buffer variables
yousefakbar Jan 24, 2026
1fee263
refactor: replace `util.find_cursor_msg_id()` with buffer-local access
yousefakbar Jan 24, 2026
8db16c0
docs(changelog): document buffer-local variables and message lookup i…
yousefakbar Jan 26, 2026
ecd72ff
fix(thread): process all root-level nodes in thread display
yousefakbar Jan 28, 2026
d6b1bd2
fix(thread): find next message when cursor is between boundaries
yousefakbar Feb 1, 2026
078e261
docs: add buffer-local variables and render_html_body documentation
yousefakbar Feb 4, 2026
09ea44a
refactor: port completion functions from vimscript to lua
antinomie8 Jan 21, 2026
a1da87f
fix(cmdline_completions): filter search results
antinomie8 Feb 6, 2026
d5453f5
refactor(completion): rename cmdline_completions module to completion
yousefakbar Feb 6, 2026
b4bf8c8
docs(changelog): document vimscript to lua migration
yousefakbar Feb 6, 2026
84b1104
docs: update documentation for vimscript to lua migration
yousefakbar Feb 6, 2026
5374489
refactor(ftplugin): migrate tag completion to lua module
yousefakbar Feb 6, 2026
7c9b1d9
Merge remote-tracking branch 'upstream'
jugarpeupv Feb 7, 2026
4d4188b
Merge branch 'fix/previous_list_messages'
jugarpeupv Feb 7, 2026
169125e
Merge remote-tracking branch 'upstream'
jugarpeupv Feb 11, 2026
07b63c9
Merge remote-tracking branch 'upstream'
jugarpeupv Feb 16, 2026
23245c9
feat(thread): add configurable message order in thread view
jugarpeupv Feb 18, 2026
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
1 change: 1 addition & 0 deletions lua/notmuch/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ C.defaults = function()
},
suppress_deprecation_warning = false, -- Used for API deprecation warning suppression
render_html_body = false, -- True means prioritize displaying rendered HTML
message_order = "newest-first", -- "newest-first" | "oldest-first" - Order of messages in thread view
open_handler = function(attachment)
require('notmuch.handlers').default_open_handler(attachment)
end,
Expand Down
7 changes: 7 additions & 0 deletions lua/notmuch/handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ H.default_view_handler = function(attachment)
local filetype = vim.fn.system({ 'file', '--mime-type', '-b', path }):gsub('%s+$', '')
local ext = path:match('%.([^%.]+)$') or ''

-- Calendar files (most common)
if filetype:match('text/calendar') or ext:match('^calendar?$') then
return try_commands({
{ tool = 'render-calendar-attachment.py', command = function(p) return { 'render-calendar-attachment.py', p } end },
}) or "Calendar file (download render-calendar-attachment.py [https://github.com/ceuk/mutt_dotfiles/tree/master/bin] to view)"
end

-- HTML files (most common)
if filetype:match('^text/html$') or ext:match('^html?$') then
return try_commands({
Expand Down
50 changes: 44 additions & 6 deletions lua/notmuch/thread.lua
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ end
--- @param depth number Message depth in the thread chain (0 for root message)
--- @param lines table Accumulator array for buffer lines (modified in place)
--- @param metadata table Accumulator array for thread metadata for buffer var
local function build_message_lines(msg_node, depth, lines, metadata)
--- @param skip_replies boolean If true, don't process replies recursively (for flattened view)
local function build_message_lines(msg_node, depth, lines, metadata, skip_replies)
-- Unpack msg_node into message and list of replies
local msg = msg_node[1]
local replies = msg_node[2] or {}
Expand Down Expand Up @@ -285,10 +286,11 @@ local function build_message_lines(msg_node, depth, lines, metadata)
attachment_count = select(2, has_attachments(msg.body)),
})

-- Process replies recursively
if replies and #replies > 0 then
-- Process replies recursively (only if not skipping)
if not skip_replies and replies and #replies > 0 then
-- Process replies in original order (maintaining hierarchy)
for _, reply_node in ipairs(replies) do
build_message_lines(reply_node, depth + 1, lines, metadata)
build_message_lines(reply_node, depth + 1, lines, metadata, false)
end
end
end
Expand Down Expand Up @@ -471,8 +473,44 @@ T.show_thread = function(threadid)

-- Build buffer lines (also builds accumulated thread metadata)
local lines = {}
for _, node in ipairs(thread) do
build_message_lines(node, 0, lines, metadata)

-- Check if we need to sort messages by timestamp
local config = require('notmuch.config')
local should_reverse = config.options.message_order == "newest-first"

if should_reverse then
-- Flatten all messages in the thread tree with their timestamps
local function flatten_messages(nodes, depth, flat_list)
for _, node in ipairs(nodes) do
local msg = node[1]
local replies = node[2] or {}
table.insert(flat_list, {
node = node,
depth = depth,
timestamp = msg.timestamp or 0
})
if #replies > 0 then
flatten_messages(replies, depth + 1, flat_list)
end
end
end

-- Flatten all messages
local flat_messages = {}
flatten_messages(thread, 0, flat_messages)

-- Sort by timestamp (newest first)
table.sort(flat_messages, function(a, b) return a.timestamp > b.timestamp end)

-- Build lines for sorted messages (with depth set to 0 to remove indentation, skip_replies = true)
for _, item in ipairs(flat_messages) do
build_message_lines(item.node, 0, lines, metadata, true)
end
else
-- Process messages in original order (oldest first, maintaining hierarchy)
for _, node in ipairs(thread) do
build_message_lines(node, 0, lines, metadata, false)
end
end

-- Set metadata tags based on ordered list of seen tags during recursion
Expand Down