summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2023-10-21 21:46:07 -0500
committerToby Vincent <tobyv@tobyvin.dev>2023-10-21 21:46:07 -0500
commitcc69cfc85ce5abd4975c020b89015dc58e056208 (patch)
tree18fb22a6769f29948dd4bfa1eefbab5f2d26f6c0
parent29cb0cd012bb377178fe8fa7426456b1cc8ab55f (diff)
feat: add predefined filters
-rwxr-xr-xfilters/html11
-rw-r--r--lua/inbox/config.lua29
-rw-r--r--lua/inbox/filters/w3m.lua21
-rw-r--r--lua/inbox/indexers/notmuch.lua41
-rw-r--r--lua/inbox/types.lua3
-rw-r--r--lua/inbox/view.lua103
6 files changed, 123 insertions, 85 deletions
diff --git a/filters/html b/filters/html
new file mode 100755
index 0000000..5ceee40
--- /dev/null
+++ b/filters/html
@@ -0,0 +1,11 @@
+#!/bin/sh
+# aerc filter which runs w3m using socksify (from the dante package) to prevent
+# any phoning home by rendered emails
+export SOCKS_SERVER="127.0.0.1:1"
+exec socksify w3m \
+ -I UTF-8 \
+ -T text/html \
+ -cols $(tput cols) \
+ -dump \
+ -o display_image=false \
+ -o display_link_number=true
diff --git a/lua/inbox/config.lua b/lua/inbox/config.lua
index 4692f5c..634b35d 100644
--- a/lua/inbox/config.lua
+++ b/lua/inbox/config.lua
@@ -54,12 +54,39 @@ local default_config = {
---@class inbox.Config
local M = {}
+function M.try_resolve(value, module)
+ if type(value) == "string" then
+ local is_ok, result = pcall(require, ("inbox.%s.%s"):format(module, value))
+ if is_ok then
+ value = result
+ end
+ end
+ return value
+end
+
+function M.parse_filters(filter_config)
+ local filters = {}
+ for content_type, items in pairs(filter_config) do
+ filters[content_type] = {}
+ for _, value in pairs(items) do
+ table.insert(filters[content_type], M.try_resolve(value, "filters"))
+ end
+ end
+ return filters
+end
+
---@param opts inbox.Config
function M.setup(opts)
local config = vim.tbl_deep_extend("keep", opts or {}, default_config)
for k, v in pairs(config) do
- M[k] = v
+ if k == "filters" then
+ M[k] = M.parse_filters(v)
+ elseif k == "indexer" then
+ M[k] = M.try_resolve(v, k)
+ else
+ M[k] = v
+ end
end
end
diff --git a/lua/inbox/filters/w3m.lua b/lua/inbox/filters/w3m.lua
new file mode 100644
index 0000000..e64781f
--- /dev/null
+++ b/lua/inbox/filters/w3m.lua
@@ -0,0 +1,21 @@
+local M = {
+ command = "socksify",
+ args = function(bufnr)
+ return {
+ "w3m",
+ "-I",
+ "UTF-8",
+ "-T",
+ "text/html",
+ "-cols",
+ vim.bo[bufnr].textwidth,
+ "-dump",
+ "-o",
+ "display_image=false",
+ "-o",
+ "display_link_number=true",
+ }
+ end,
+}
+
+return M
diff --git a/lua/inbox/indexers/notmuch.lua b/lua/inbox/indexers/notmuch.lua
index 83f9ac9..a05c112 100644
--- a/lua/inbox/indexers/notmuch.lua
+++ b/lua/inbox/indexers/notmuch.lua
@@ -188,47 +188,6 @@ function M.flatten_parts(part, parts)
return parts
end
-function M.get_part(id, content_type, callback)
- local entry = M.cache(id)
-
- if entry == nil then
- utils.error("Failed to get entry", { id = id })
- return
- end
-
- ---@type inbox.EntryPart?
- local part
-
- for _, p in pairs(entry.parts) do
- if content_type == nil or p["content-type"] == content_type then
- part = p
- break
- end
- end
-
- vim.print(part)
-
- if part == nil then
- utils.error("Failed to find message part for entry", { id = id, ["content-type"] = content_type })
- return
- end
-
- local job = Job:new({
- command = "notmuch",
- args = { "show", ("--part=%s"):format(part.id), ("id:%s"):format(entry.id) },
- on_exit = vim.schedule_wrap(function(j)
- callback(entry, j:result())
- end),
- })
-
- -- if part["content-type"] == "text/html" then
- -- job = Job:new({ command = "/usr/lib/aerc/filters/wrap", writer = job })
- -- job = Job:new({ command = "/usr/lib/aerc/filters/colorize", writer = job })
- -- end
-
- job:start()
-end
-
---@param opts inbox.Indexer.Notmuch.Config
function M.setup(opts)
local config = vim.tbl_deep_extend("keep", opts or {}, default_config)
diff --git a/lua/inbox/types.lua b/lua/inbox/types.lua
index 691f6cf..a4105b0 100644
--- a/lua/inbox/types.lua
+++ b/lua/inbox/types.lua
@@ -3,7 +3,7 @@
---@field indexer_config inbox.Indexer.Config|nil
---@field buf_options table|nil
---@field win_options table|nil
----@field filters table<inbox.ContentType, inbox.PartFilter>
+---@field filters table<inbox.ContentType, inbox.PartFilter[]>
---@field columns integer[]
---@field flags table<string, table>
---@field headers inbox.HeaderKey[]
@@ -30,7 +30,6 @@
---@field index? fun(maildir: string, cb: fun(ids: string[], entries: inbox.Summary[], signs: (string | integer)[][]), opts?: table)
---@field get_entry? fun(id: string): inbox.Entry|nil
---@field get_parts? fun(id: string): inbox.ContentType[]
----@field get_part? fun(id: string, content_type: inbox.ContentType, callback: fun(entry: inbox.Entry, part_index: integer, part_lines: string[]))
---@alias inbox.Indexer.Config
---| "notmuch"
diff --git a/lua/inbox/view.lua b/lua/inbox/view.lua
index 5c40d5f..3ba20c6 100644
--- a/lua/inbox/view.lua
+++ b/lua/inbox/view.lua
@@ -34,20 +34,22 @@ function M.render_buffer(bufnr)
end
---@param bufnr integer
----@param lines string[]
----@param start integer?
----@param end_ integer?
-function M.set_buffer_content(bufnr, lines, start, end_)
- if start == nil then
- start = 0
- end
-
- if end_ == nil then
- end_ = -1
+---@param start integer
+---@param end_ integer
+---@param strict_indexing boolean
+---@param lines string[]?
+---@param escape_ascii boolean?
+function M.buf_set_lines(bufnr, start, end_, strict_indexing, lines, escape_ascii)
+ local buf_writer
+ if escape_ascii and pcall(require, "baleia") then
+ local baleia = require("baleia").setup()
+ buf_writer = baleia.buf_set_lines
+ else
+ buf_writer = vim.api.nvim_buf_set_lines
end
vim.bo[bufnr].modifiable = true
- vim.api.nvim_buf_set_lines(bufnr, start, end_, true, lines)
+ buf_writer(bufnr, start, end_, strict_indexing, lines or {})
vim.bo[bufnr].modifiable = false
vim.bo[bufnr].modified = false
end
@@ -84,7 +86,7 @@ function M.render_inbox(bufnr, maildir)
vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid })
end
- M.set_buffer_content(bufnr, lines)
+ M.buf_set_lines(bufnr, 0, -1, true, lines)
utils.set_highlights(bufnr, highlights)
utils.set_signs(bufnr, signs)
@@ -141,6 +143,25 @@ function M.initialize_entry(maildir, id, content_type)
M.render_headers(bufnr, id)
M.render_entry(bufnr, id, content_type)
+ vim.api.nvim_create_autocmd({ "BufModifiedSet", "BufWinEnter" }, {
+ group = "Inbox",
+ buffer = bufnr,
+ callback = function()
+ for _, winid in pairs(vim.fn.win_findbuf(bufnr)) do
+ local winbar = string.format(
+ "%sPart: %s",
+ string.rep(" ", vim.fn.getwininfo(winid)[1].textoff),
+ vim.b[bufnr].inbox_content_type
+ )
+
+ vim.api.nvim_set_option_value("winbar", winbar, {
+ scope = "local",
+ win = winid,
+ })
+ end
+ end,
+ })
+
return bufnr
end
@@ -172,13 +193,10 @@ function M.render_headers(bufnr, id)
local cursor_pos = vim.fn.getpos(".")
- if vim.b[bufnr].header_count ~= nil then
- M.set_buffer_content(bufnr, {}, 0, vim.b[bufnr].header_count)
- end
-
- M.set_buffer_content(bufnr, lines, 0, 0)
+ M.buf_set_lines(bufnr, 0, vim.b[bufnr].header_lines or 0, true, {})
+ M.buf_set_lines(bufnr, 0, 0, true, lines)
- vim.b[bufnr].header_count = #lines
+ vim.b[bufnr].header_lines = #lines
vim.fn.setpos(".", cursor_pos)
end
@@ -209,34 +227,37 @@ function M.render_entry(bufnr, id, content_type)
if vim.tbl_isempty(config.filters[content_type] or {}) then
local lines = vim.split(part.content, "\n")
- M.set_buffer_content(bufnr, lines, vim.b[bufnr].header_count)
+ M.buf_set_lines(bufnr, vim.b[bufnr].header_lines or 0, -1, true, lines)
else
local job
- for i, filter in pairs(config.filters[content_type]) do
- if i == 1 then
- job = Job:new({
- command = filter.command,
- args = filter.args,
- writer = part.content,
- })
- elseif i < #config.filters[content_type] then
- job = Job:new({
- command = filter.command,
- args = filter.args,
- writer = job,
- })
+ for i, filter in pairs(config.filters[content_type] or {}) do
+ for key, value in pairs(filter) do
+ if type(value) == "function" then
+ filter[key] = value(bufnr)
+ else
+ filter[key] = value
+ end
+ end
+
+ local opts = {
+ command = filter.command,
+ args = filter.args,
+ }
+
+ if job == nil then
+ opts.writer = part.content
else
- job = Job:new({
- command = filter.command,
- args = filter.args,
- writer = job,
- on_exit = vim.schedule_wrap(function(self)
- vim.print(self)
- M.set_buffer_content(bufnr, self:result(), vim.b[bufnr].header_count)
- end),
- })
+ opts.writer = job
end
+
+ if i == #config.filters[content_type] then
+ opts.on_exit = vim.schedule_wrap(function(self)
+ M.buf_set_lines(bufnr, vim.b[bufnr].header_lines or 0, -1, true, self:result(), true)
+ end)
+ end
+
+ job = Job:new(opts)
end
job:start()