aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md38
-rw-r--r--after/plugin/cmp_abook.lua1
-rw-r--r--lua/cmp_abook/init.lua99
-rw-r--r--preview.gifbin0 -> 301495 bytes
4 files changed, 138 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..007de42
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# cmp-abook
+
+A completion source for [nvim-cmp][nvim-cmp] that provides sources for addresses
+in [Abook][abook] when writing emails.
+
+![](preview.gif)
+
+## Dependencies
+
+- [plenary.nvim][plenary.nvim]
+
+## Setup
+
+Just add the `abook` source to [nvim-cmp][nvim-cmp] setup call:
+
+``` lua
+sources = {
+ -- Most names in an address book have spaces in them. However, cmp restarts
+ -- the completion after a space. The `space_filter` option is a way to get
+ -- around this by using a different character to represent spaces.
+ { name = "abook", option = { space_filter = "-" } }
+}
+```
+
+### Multiple addressbooks
+
+By default the plugin uses the default addressbook. You can use the
+`ABOOK_ADDRESSBOOK` environment variable option to control which addressbook to
+use. If you're using `mutt` for email, you could set it like this:
+
+```
+set editor="ABOOK_ADDRESSBOOK='$HOME/.config/abook/my_custom_addressbook' nvim ...other options... %s"
+```
+
+---
+[plenary.nvim]: https://github.com/nvim-lua/plenary.nvim
+[abook]: https://abook.sourceforge.io/
+[nvim-cmp]: https://github.com/hrsh7th/nvim-cmp
diff --git a/after/plugin/cmp_abook.lua b/after/plugin/cmp_abook.lua
new file mode 100644
index 0000000..a5bf249
--- /dev/null
+++ b/after/plugin/cmp_abook.lua
@@ -0,0 +1 @@
+require('cmp').register_source('abook', require('cmp_abook').new())
diff --git a/lua/cmp_abook/init.lua b/lua/cmp_abook/init.lua
new file mode 100644
index 0000000..0388b60
--- /dev/null
+++ b/lua/cmp_abook/init.lua
@@ -0,0 +1,99 @@
+local has_cmp, cmp = pcall(require, "cmp")
+if not has_cmp then
+ return
+end
+
+local has_job, Job = pcall(require, "plenary.job")
+if not has_job then
+ return
+end
+
+local source = {}
+local defaults = {
+ space_filter = "-",
+ address_book = nil,
+}
+
+source.new = function()
+ return setmetatable({}, { __index = source })
+end
+
+function source:is_available()
+ return vim.bo.filetype == "mail"
+end
+function source:get_debug_name()
+ return "abook"
+end
+
+function source:complete(params, callback)
+ params.option = vim.tbl_deep_extend("keep", params.option, defaults)
+ vim.validate(
+ "params.option.space_filter",
+ params.option.space_filter,
+ { "string" }
+ )
+
+ local ctx = params.context
+
+ if
+ not (
+ ctx.cursor_line:match("^To: ")
+ or ctx.cursor_line:match("^Cc: ")
+ or ctx.cursor_line:match("^Bcc: ")
+ )
+ then
+ callback({})
+ return
+ end
+
+ local query = ""
+ local line = ctx.cursor_line
+ local cursor = ctx.cursor.character
+ for i = cursor, 1, -1 do
+ local char = line:sub(i, i)
+ if char == ":" or char == "," then
+ query = line:sub(i + 2, cursor)
+ break
+ end
+ end
+
+ local abook_addressbook = os.getenv("ABOOK_ADDRESSBOOK")
+ local abook_args = { "--mutt-query", query }
+ if abook_addressbook then
+ table.insert(abook_args, "-f")
+ table.insert(abook_args, abook_addressbook)
+ end
+
+ Job
+ :new({
+ command = "abook",
+ args = abook_args,
+ on_exit = function(job, code)
+ if code ~= 0 then
+ return
+ end
+
+ local result = job:result()
+
+ local items = {}
+ for _, item in ipairs(result) do
+ local item_parts = vim.split(item, "\t", { trimempty = true })
+ local label = string.format(
+ "%s <%s>",
+ item_parts[2],
+ item_parts[1]
+ ) or item_parts[1]
+ table.insert(items, {
+ label = label,
+ filterText = label:gsub(" ", params.option.space_filter),
+ kind = cmp.lsp.CompletionItemKind.Text,
+ })
+ end
+
+ callback({ items = items, isIncomplete = false })
+ end,
+ })
+ :start()
+end
+
+return source
diff --git a/preview.gif b/preview.gif
new file mode 100644
index 0000000..771d0a4
--- /dev/null
+++ b/preview.gif
Binary files differ