-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nvim(completion): Add new sources for gitcommit
This includes handle completion (requires `sort`, `git` and `jq`) and keyword completion.
- Loading branch information
Showing
3 changed files
with
256 additions
and
55 deletions.
There are no files selected for viewing
76 changes: 76 additions & 0 deletions
76
.config/nvim/lua/completion-sources/gitcommit-keywords.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
local M = {} | ||
|
||
local registered = false | ||
|
||
M.setup = function(handle_file) | ||
if registered then | ||
return | ||
end | ||
registered = true | ||
|
||
local has_cmp, cmp = pcall(require, 'cmp') | ||
if not has_cmp then | ||
return | ||
end | ||
|
||
local source = {} | ||
|
||
source.new = function() | ||
return setmetatable({}, {__index = source}) | ||
end | ||
|
||
source.get_keyword_pattern = function() | ||
-- Add dot to existing keyword characters (\k). | ||
return [[\%(\k\|\.\)\+]] | ||
end | ||
|
||
source.complete = function(_, request, callback) | ||
local input = string.sub(request.context.cursor_before_line, request.offset - 1) | ||
-- local prefix = string.sub(request.context.cursor_before_line, 1, request.offset - 1) | ||
|
||
local gitcommit_keywords = { | ||
'Addresses:', | ||
'Co-Authored-By:', | ||
'Resolves:', | ||
'Approved-by:', | ||
'Reviewed-by:', | ||
'Signed-off-by:', | ||
} | ||
|
||
if request.context.cursor.col <= 2 then | ||
local items = {} | ||
for _, keyword in ipairs(gitcommit_keywords) do | ||
table.insert(items, { | ||
filterText = keyword, | ||
label = keyword, | ||
textEdit = { | ||
newText = keyword, | ||
range = { | ||
start = { | ||
line = request.context.cursor.row - 1, | ||
character = request.context.cursor.col - 1 - #input, | ||
}, | ||
['end'] = { | ||
line = request.context.cursor.row - 1, | ||
character = request.context.cursor.col - 1, | ||
}, | ||
}, | ||
}, | ||
} | ||
) | ||
end | ||
callback { | ||
items = items, | ||
isIncomplete = true, | ||
} | ||
else | ||
callback({isIncomplete = true}) | ||
end | ||
end | ||
|
||
cmp.register_source('gitcommit_keywords', source.new()) | ||
|
||
end | ||
|
||
return M | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
local handles = {} | ||
|
||
local Job = require('plenary.job') | ||
|
||
local registered = false | ||
|
||
local register_source = function(json_string) | ||
if registered then | ||
return | ||
end | ||
registered = true | ||
|
||
local has_cmp, cmp = pcall(require, 'cmp') | ||
if not has_cmp then | ||
return | ||
end | ||
local success, handles_with_names_and_emails = pcall(function() | ||
return vim.fn.json_decode(json_string) | ||
end) | ||
|
||
if not success then | ||
return | ||
end | ||
|
||
local source = {} | ||
|
||
source.new = function() | ||
return setmetatable({}, {__index = source}) | ||
end | ||
|
||
source.get_trigger_characters = function() | ||
return { '@' } | ||
end | ||
|
||
source.get_keyword_pattern = function() | ||
-- Add dot to existing keyword characters (\k). | ||
return [[\%(\k\|\.\)\+]] | ||
end | ||
|
||
source.complete = function(_, request, callback) | ||
local input = string.sub(request.context.cursor_before_line, request.offset - 1) | ||
local prefix = string.sub(request.context.cursor_before_line, 1, request.offset - 1) | ||
|
||
if vim.startswith(input, '@') and (prefix == '@' or vim.endswith(prefix, ' @')) then | ||
local items = {} | ||
for handle, name_and_email in pairs(handles_with_names_and_emails) do | ||
table.insert(items, { | ||
filterText = handle .. ' ' .. name_and_email, | ||
label = name_and_email, | ||
textEdit = { | ||
newText = name_and_email, | ||
range = { | ||
start = { | ||
line = request.context.cursor.row - 1, | ||
character = request.context.cursor.col - 1 - #input, | ||
}, | ||
['end'] = { | ||
line = request.context.cursor.row - 1, | ||
character = request.context.cursor.col - 1, | ||
}, | ||
}, | ||
}, | ||
} | ||
) | ||
end | ||
callback { | ||
items = items, | ||
isIncomplete = true, | ||
} | ||
else | ||
callback({isIncomplete = true}) | ||
end | ||
end | ||
|
||
cmp.register_source('handles', source.new()) | ||
end | ||
|
||
handles.setup = function() | ||
local json_lines = {} | ||
|
||
Job:new({ | ||
command = 'jq', | ||
args = {'-s', '--compact-output', [[ | ||
map (select(keys[] != "jenkins" and keys[] != "terrier-lottery-results-domain")) | ||
| reduce .[] as $item ({}; . + $item) | ||
]]}, | ||
writer = Job:new({ | ||
command = 'sed', | ||
args = {'-r', '-e', '/<>/d', | ||
'-e', 's/"//g', | ||
'-e', 's/^(.*<([^@]+)@.*)$/{"\\2": "\\1"}/'}, | ||
writer = Job:new({ | ||
command = 'sort', | ||
args = {'-u'}, | ||
writer = Job:new({ | ||
command = 'git', | ||
args = { 'log', '--oneline', '--format=format:%aN <%ae>'}, | ||
}), | ||
}), | ||
}), | ||
on_stdout = function(_, line) | ||
table.insert(json_lines, line) | ||
end, | ||
on_exit = function(_, _) | ||
local timer = vim.loop.new_timer() | ||
timer:start(0, 0, vim.schedule_wrap(function() | ||
register_source(json_lines) | ||
end)) | ||
end | ||
}):start() | ||
|
||
end | ||
|
||
|
||
return handles | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,76 @@ | ||
local M = {} | ||
|
||
function M.setup () | ||
-- vim.g.cpp_simple_highlight = 1 | ||
local setup_cmp = function() | ||
local cmp = require('cmp') | ||
|
||
vim.cmd[[hi default LspCxxHlGroupNamespace ctermfg=Yellow guifg=#E5C07B cterm=none gui=none]] | ||
vim.cmd[[hi default LspCxxHlGroupMemberVariable ctermfg=White guifg=#F16E77]] | ||
cmp.setup({ | ||
snippet = { | ||
expand = function(args) | ||
-- vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users. | ||
require('luasnip').lsp_expand(args.body) -- For `luasnip` users. | ||
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users. | ||
-- require'snippy'.expand_snippet(args.body) -- For `snippy` users. | ||
end, | ||
}, | ||
mapping = { | ||
['<c-n>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<c-p>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<Tab>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<S-Tab>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }), | ||
['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }), | ||
['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }), | ||
['<C-y>'] = cmp.config.disable, -- If you want to remove the default `<C-y>` mapping, You can specify `cmp.config.disable` value. | ||
['<C-e>'] = cmp.mapping({ | ||
i = cmp.mapping.abort(), | ||
c = cmp.mapping.close(), | ||
}), | ||
['<CR>'] = nil, | ||
['<C-c>'] = cmp.mapping.confirm({ select = true }), | ||
}, | ||
sources = cmp.config.sources({ | ||
{ name = 'neorg' }, | ||
{ name = 'nvim_lsp' }, | ||
-- { name = 'vsnip' }, -- For vsnip users. | ||
-- { name = 'ultisnips' }, -- For ultisnips users. | ||
-- { name = 'snippy' }, -- For snippy users. | ||
{ name = 'path' }, | ||
{ name = 'buffer' }, | ||
}) | ||
}) | ||
|
||
local cmp = require'cmp' | ||
-- Use buffer source for `/`. | ||
cmp.setup.cmdline('/', { | ||
sources = { | ||
{ name = 'buffer' }, | ||
} | ||
}) | ||
|
||
cmp.setup({ | ||
snippet = { | ||
expand = function(args) | ||
-- vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users. | ||
require('luasnip').lsp_expand(args.body) -- For `luasnip` users. | ||
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users. | ||
-- require'snippy'.expand_snippet(args.body) -- For `snippy` users. | ||
end, | ||
}, | ||
mapping = { | ||
['<c-n>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<c-p>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<Tab>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<S-Tab>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), | ||
['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }), | ||
['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }), | ||
['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }), | ||
['<C-y>'] = cmp.config.disable, -- If you want to remove the default `<C-y>` mapping, You can specify `cmp.config.disable` value. | ||
['<C-e>'] = cmp.mapping({ | ||
i = cmp.mapping.abort(), | ||
c = cmp.mapping.close(), | ||
}), | ||
['<CR>'] = nil, | ||
['<C-c>'] = cmp.mapping.confirm({ select = true }), | ||
}, | ||
sources = cmp.config.sources({ | ||
{ name = 'neorg' }, | ||
{ name = 'nvim_lsp' }, | ||
-- { name = 'vsnip' }, -- For vsnip users. | ||
{ name = 'luasnip' }, -- For luasnip users. | ||
-- { name = 'ultisnips' }, -- For ultisnips users. | ||
-- { name = 'snippy' }, -- For snippy users. | ||
{ name = 'path' }, | ||
}, { | ||
{ name = 'buffer' }, | ||
}) | ||
}) | ||
-- Use cmdline & path source for ':'. | ||
cmp.setup.cmdline(':', { | ||
sources = cmp.config.sources({ | ||
{ name = 'path' }, | ||
{ name = 'cmdline' }, | ||
}) | ||
}) | ||
|
||
-- Use buffer source for `/`. | ||
cmp.setup.cmdline('/', { | ||
sources = { | ||
{ name = 'buffer' }, | ||
} | ||
}) | ||
cmp.setup.filetype('gitcommit', { | ||
sources = cmp.config.sources({ | ||
{ name = 'handles' }, | ||
{ name = 'gitcommit_keywords' }, | ||
}), | ||
}) | ||
end | ||
|
||
-- Use cmdline & path source for ':'. | ||
cmp.setup.cmdline(':', { | ||
sources = cmp.config.sources({ | ||
{ name = 'path' } | ||
}, { | ||
{ name = 'cmdline' } | ||
}) | ||
}) | ||
require('completion-sources.handles').setup() | ||
require('completion-sources.gitcommit-keywords').setup() | ||
setup_cmp() | ||
|
||
end | ||
|
||
vim.cmd[[hi default LspCxxHlGroupNamespace ctermfg=Yellow guifg=#E5C07B cterm=none gui=none]] | ||
vim.cmd[[hi default LspCxxHlGroupMemberVariable ctermfg=White guifg=#F16E77]] | ||
|
||
|
||
return M |