From a3e2977d898e60e34aaf8f681ef8a5413eaa55fd Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Mon, 16 Oct 2023 18:14:48 -0500 Subject: feat: add signs for tags --- lua/inbox/config.lua | 38 +++++++++++++++++--- lua/inbox/email.lua | 80 ------------------------------------------ lua/inbox/indexers/notmuch.lua | 56 +++++++++++++++++++++++++---- lua/inbox/init.lua | 6 ++++ lua/inbox/types.lua | 44 +++++++++++++++++++++++ lua/inbox/utils.lua | 6 ++++ lua/inbox/view.lua | 40 +++++++++------------ 7 files changed, 155 insertions(+), 115 deletions(-) delete mode 100644 lua/inbox/email.lua create mode 100644 lua/inbox/types.lua diff --git a/lua/inbox/config.lua b/lua/inbox/config.lua index 1ba2566..db122f8 100644 --- a/lua/inbox/config.lua +++ b/lua/inbox/config.lua @@ -2,6 +2,8 @@ ---@field indexer_config inbox.Indexer.Config|nil ---@field buf_options table|nil ---@field win_options table|nil +---@field columns integer[] +---@field signs table ---@type inbox.Config local default_config = { @@ -15,21 +17,49 @@ local default_config = { }, win_options = { wrap = false, - signcolumn = "yes:3", -- can signs be used for flags?? - number = false, - relativenumber = false, + signcolumn = "auto", cursorcolumn = false, + colorcolumn = false, foldcolumn = "0", spell = false, list = false, }, + columns = { + 15, + 30, + }, + signs = { + attachment = { + text = "A", + texthl = "Constant", + }, + draft = { + text = "D", + }, + flagged = { + text = "F", + texthl = "Search", + }, + passed = { + text = "P", + }, + replied = { + text = "R", + texthl = "Directory", + }, + unread = { + text = "S", + texthl = "Special", + linehl = "Special", + }, + }, } ---@class inbox.Config local M = {} ---@param opts inbox.Config -M.setup = function(opts) +function M.setup(opts) local config = vim.tbl_deep_extend("keep", opts or {}, default_config) for k, v in pairs(config) do diff --git a/lua/inbox/email.lua b/lua/inbox/email.lua deleted file mode 100644 index c680b16..0000000 --- a/lua/inbox/email.lua +++ /dev/null @@ -1,80 +0,0 @@ ----@class inbox.Summary ----@field authors string | string[] ----@field date_relative string ----@field matched integer ----@field query string[] ----@field subject string | string[] ----@field tags string[] ----@field thread integer ----@field timestamp integer ----@field total integer - ----@class inbox.Email ----@field id string ----@field filename string[] ----@field timestamp integer ----@field date_relative string? ----@field tags string[] ----@field duplicate integer ----@field body inbox.Part[] ----@field crypto table ----@field headers inbox.Headers - ----@alias inbox.Headers table - ----@alias inbox.Header ----| "Subject" ----| "Date" ----| "To" ----| "From" ----| string - ----@class inbox.Part ----@field id integer ----@field content-type inbox.ContentType ----@field content-charset? string ----@field content-length? integer ----@field content-disposition? string ----@field content-transfer-encoding? string ----@field content? string | inbox.Part[] - ----@alias inbox.ContentType ----| "text/plain" ----| "text/html" ----| string - -local M = {} - -M.summary_widths = { - 10, - 30, -} - ----@param summary inbox.Summary ----@return table sanitized sanitized summary -function M.sanitize_summary(summary) - local date = summary.date_relative:gsub("^([A-Z][a-z][a-z])%w%w+", "%1.") - - local from - if type(summary.authors) == "table" then - from = summary.authors[1] --[[@as string]] - else - from = summary.authors --[[@as string]] - end - - local subject - if type(summary.subject) == "table" then - subject = summary.subject[1] --[[@as string]] - else - subject = summary.subject --[[@as string]] - end - subject = subject:gsub("\r?\n", " ") - - return { - date, - from, - subject, - } -end - -return M diff --git a/lua/inbox/indexers/notmuch.lua b/lua/inbox/indexers/notmuch.lua index 171fabf..c13e898 100644 --- a/lua/inbox/indexers/notmuch.lua +++ b/lua/inbox/indexers/notmuch.lua @@ -4,6 +4,7 @@ local Path = require("plenary.path") ---@class inbox.Indexer.Notmuch.Config local default_config = { database_dir = Path:new(vim.env.XDG_DATA_HOME, "mail").filename, + map_tag_signs = {}, } ---@class inbox.Indexer.Notmuch: inbox.Indexer, inbox.Indexer.Notmuch.Config @@ -24,12 +25,27 @@ function M.index(callback, filters) json = json .. stdout end), on_exit = vim.schedule_wrap(function(_, _, _) - if json == "" then - json = "[]" + local entries = {} + + if json and json ~= "" then + entries = vim.json.decode(json) or {} + end + + local rows = {} + local signs = {} + + for lnum, entry in ipairs(entries) do + local cols = M.summarize(entry) + + for _, tag in ipairs(entry.tags) do + local sign = M.map_tag_signs[tag] or tag + table.insert(signs, { sign, lnum }) + end + + table.insert(rows, cols) end - local entries = vim.json.decode(json) - callback(entries) + callback(rows, signs) end), }) @@ -38,16 +54,42 @@ function M.index(callback, filters) for name, value in pairs(filters) do table.insert(filter_args, ("%s:%s"):format(name, value)) end + local filter_args_str = table.concat(filter_args, " and ") vim.list_extend(job.args, vim.split(filter_args_str, " ")) - vim.print(job.args) - job:start() end +---@param summary inbox.Summary +---@return table sanitized sanitized summary +function M.summarize(summary) + local date = summary.date_relative + + local from + if type(summary.authors) == "table" then + from = summary.authors[1] --[[@as string]] + else + from = summary.authors --[[@as string]] + end + + local subject + if type(summary.subject) == "table" then + subject = summary.subject[1] --[[@as string]] + else + subject = summary.subject --[[@as string]] + end + subject = subject:gsub("\r?\n", " ") + + return { + date, + from, + subject, + } +end + ---@param opts inbox.Indexer.Notmuch.Config -M.setup = function(opts) +function M.setup(opts) local config = vim.tbl_deep_extend("keep", opts or {}, default_config) for k, v in pairs(config) do diff --git a/lua/inbox/init.lua b/lua/inbox/init.lua index 5841481..b00ed84 100644 --- a/lua/inbox/init.lua +++ b/lua/inbox/init.lua @@ -15,9 +15,15 @@ end function M.setup(opts) local config = require("inbox.config") local indexers = require("inbox.indexers") + local utils = require("inbox.utils") config.setup(opts) indexers.setup(config.indexer_config) + + for sign, value in pairs(config.signs) do + local name = utils.sign_name(sign) + vim.fn.sign_define(name, value) + end end return M diff --git a/lua/inbox/types.lua b/lua/inbox/types.lua new file mode 100644 index 0000000..1d2c549 --- /dev/null +++ b/lua/inbox/types.lua @@ -0,0 +1,44 @@ +---@class inbox.Summary +---@field authors string | string[] +---@field date_relative string +---@field matched integer +---@field query string[] +---@field subject string | string[] +---@field tags string[] +---@field thread integer +---@field timestamp integer +---@field total integer + +---@class inbox.Email +---@field id string +---@field filename string[] +---@field timestamp integer +---@field date_relative string? +---@field tags string[] +---@field duplicate integer +---@field body inbox.Part[] +---@field crypto table +---@field headers inbox.Headers + +---@alias inbox.Headers table + +---@alias inbox.Header +---| "Subject" +---| "Date" +---| "To" +---| "From" +---| string + +---@class inbox.Part +---@field id integer +---@field content-type inbox.ContentType +---@field content-charset? string +---@field content-length? integer +---@field content-disposition? string +---@field content-transfer-encoding? string +---@field content? string | inbox.Part[] + +---@alias inbox.ContentType +---| "text/plain" +---| "text/html" +---| string diff --git a/lua/inbox/utils.lua b/lua/inbox/utils.lua index 93b4d47..ddc809d 100644 --- a/lua/inbox/utils.lua +++ b/lua/inbox/utils.lua @@ -77,4 +77,10 @@ function M.render_winbar(winid, cols, col_widths) vim.api.nvim_set_option_value("winbar", string.rep(" ", offset) .. winbar, { scope = "local", win = winid }) end +---@param name string +---@return string sign_name +function M.sign_name(name) + return "Inbox" .. name:gsub("^%l", string.upper) +end + return M diff --git a/lua/inbox/view.lua b/lua/inbox/view.lua index cfe256c..252bef3 100644 --- a/lua/inbox/view.lua +++ b/lua/inbox/view.lua @@ -1,5 +1,4 @@ local config = require("inbox.config") -local email = require("inbox.email") local indexers = require("inbox.indexers") local utils = require("inbox.utils") @@ -44,45 +43,38 @@ function M.render_buffer(bufnr) return false end - local function render_buffer_async_callback(entries) + local function render_buffer_async_callback(entries, signs) -- TODO: sort entries? - utils.render_table({ {} }, email.summary_widths) - - local summaries = {} - - -- local signs - for _, entry in ipairs(entries) do - local cols = email.sanitize_summary(entry) - - -- TODO: format signs - -- local _ = email.tags - -- table.insert(signs, email.tags) - - table.insert(summaries, cols) - end - - -- TODO: configurable table columns and column widths - - local lines, _ = utils.render_table(summaries, email.summary_widths) + local lines, _ = utils.render_table(entries, config.columns) -- TODO: setup highlights - -- TODO: setup signs (tags) vim.bo[bufnr].modifiable = true vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines) vim.bo[bufnr].modifiable = false vim.bo[bufnr].modified = false + for _, sign_lnum in pairs(signs) do + local sign, lnum = unpack(sign_lnum) + local name = utils.sign_name(sign) + + if #vim.fn.sign_getdefined(name) > 0 then + vim.fn.sign_place(0, "inbox", name, bufnr, { lnum = lnum }) + end + end + local winid = vim.api.nvim_get_current_win() for k, v in pairs(config.win_options) do vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) end - local winbar = utils.render_row({ "Date", "From", "Subject" }, email.summary_widths) - local offset = vim.fn.getwininfo(winid)[1].textoff + 1 - vim.api.nvim_set_option_value("winbar", string.rep(" ", offset) .. winbar, { scope = "local", win = winid }) + local offset = vim.fn.getwininfo(winid)[1].textoff + local winbar_col = config.columns + table.insert(winbar_col, 1, offset) + local winbar = utils.render_row({ "Flags", "Date", "From", "Subject" }, winbar_col) + vim.api.nvim_set_option_value("winbar", winbar, { scope = "local", win = winid }) end -- TODO: cache entries -- cgit v1.2.3-70-g09d2