Git source for hrsh7th/nvim-cmp and Saghen/blink.cmp.
| Git | Trigger |
|---|---|
| Commits | : |
| Trailer keys | A word at the start of a line in a commit message |
| Trailer identities | Name <email> after an identity key, such as Co-authored-by: |
| Trailer values | An earlier value of the key after any other key, such as Assisted-by: |
| GitHub | Trigger |
|---|---|
| Issues | # |
| Mentions | @ |
| Pull Requests | # |
| GitLab | Trigger |
|---|---|
| Issues | # |
| Mentions | @ |
| Merge Requests | ! |
| Gitea and Forgejo | Trigger |
|---|---|
| Issues | # |
| Mentions | @ |
| Pull Requests | #, ! |
- Neovim >= 0.12
- git (>= 2.31 to find trailer keys in history)
- curl (>= 7.55)
- GitHub CLI (optional, cmp-git uses curl if it is not available)
- GitLab CLI (optional, cmp-git uses curl if it is not available)
- tea >= 0.12.0 (optional, for Gitea, cmp-git uses curl if it is not available)
- forgejo-cli (
fj) (optional, for Forgejo, cmp-git reads the token offjand sends it with curl)
curl: Generate a token with thereposcope. Set theGITHUB_API_TOKENenvironment variable to the token.GitHub CLI: Run gh auth login.
curl: Generate a token with theapiscope. Set theGITLAB_TOKENenvironment variable to the token.GitLab CLI: Run glab auth login.
curl: Generate an access token in Settings > Applications on the server, with theread:issueandread:repositoryscopes. Set theGITEA_TOKENenvironment variable to the token.tea: Runtea login addfor the server. cmp-git uses the login whose URL is the host of the remote.
curl: Generate an access token in Settings > Applications on the server, with theread:issueandread:repositoryscopes. Set theFORGEJO_TOKENenvironment variable to the token.forgejo-cli: Runfj auth loginorfj auth add-tokenfor the server. cmp-git reads the token thatfjkeeps for the host.
Without a token, @ shows no Gitea and Forgejo mentions, also in a public repository. The assignees API needs a token.
Plug 'petertriho/cmp-git'use("petertriho/cmp-git")With nvim-cmp:
return {
"petertriho/cmp-git",
dependencies = { 'hrsh7th/nvim-cmp' },
opts = {
-- options go here
},
init = function()
table.insert(require("cmp").get_config().sources, { name = "git" })
end
}With blink.cmp:
return {
"petertriho/cmp-git",
}require("cmp").setup({
sources = {
{ name = "git" },
-- more sources
}
})
require("cmp_git").setup()If you use blink.cmp, configure cmp-git in your blink.cmp setup. Do not call require("cmp_git").setup() for
blink.cmp. That function registers the nvim-cmp source.
require("blink.cmp").setup({
sources = {
default = { "git" },
providers = {
git = {
name = "git",
module = "cmp_git.blink",
opts = {
-- cmp-git options go here
},
},
},
},
})To use cmp-git only in commit-related filetypes, add it to sources.per_filetype for these filetypes, for example
gitcommit, octo, or NeogitCommitMessage. Your normal blink.cmp sources then stay in the other filetypes.
local format = require("cmp_git.format")
local sort = require("cmp_git.sort")
require("cmp_git").setup({
-- defaults
filetypes = { "gitcommit", "octo", "NeogitCommitMessage" },
remotes = { "upstream", "origin" }, -- in order of most to least prioritized
enableRemoteUrlRewrites = false, -- enable git url rewrites, see https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf
ssh_aliases = {}, -- SSH host aliases and their real hosts, such as { ["github-work"] = "github.com" }
cache = {
ttl = 300, -- seconds after which a request also gets the items again in the background
},
git = {
commits = {
limit = 100,
sort_by = sort.git.commits,
format = format.git.commits,
sha_length = 7,
},
trailers = {
filetypes = { "gitcommit", "NeogitCommitMessage" },
min_line = 3, -- first line where trailers complete, below the subject and its blank line
keys = {
builtin = {
"Co-authored-by", "Signed-off-by", "Reviewed-by", "Acked-by", "Tested-by",
"Reported-by", "Suggested-by", "Helped-by", "Fixes", "Closes", "Refs",
},
limit = 100, -- commits scanned for keys
sort_by = sort.git.trailers.keys,
format = format.git.trailers.keys,
},
identities = {
-- trailer keys whose values are completed with `Name <email>`
keys = {
"Co-authored-by", "Signed-off-by", "Reviewed-by", "Acked-by", "Tested-by",
"Reported-by", "Suggested-by", "Helped-by",
},
limit = 1000, -- commits scanned for identities
sort_by = sort.git.trailers.identities,
format = format.git.trailers.identities,
},
-- earlier values of the current key, for keys that `identities` does not handle
values = {
limit = 1000, -- commits scanned for values
sort_by = sort.git.trailers.values,
format = format.git.trailers.values,
},
},
},
github = {
hosts = {}, -- list of private instances of github
issues = {
fields = { "title", "number", "body", "updatedAt", "state" },
filter = "all", -- all, assigned, created, mentioned
limit = 100,
state = "open", -- open, closed, all
sort_by = sort.github.issues,
format = format.github.issues,
},
mentions = {
limit = 100,
sort_by = sort.github.mentions,
format = format.github.mentions,
},
pull_requests = {
fields = { "title", "number", "body", "updatedAt", "state" },
limit = 100,
state = "open", -- open, closed, merged, all
sort_by = sort.github.pull_requests,
format = format.github.pull_requests,
},
},
gitlab = {
hosts = {}, -- list of private instances of gitlab, with the path prefix if any, such as "example.com/gitlab"
issues = {
limit = 100,
state = "opened", -- opened, closed, all
sort_by = sort.gitlab.issues,
format = format.gitlab.issues,
},
mentions = {
limit = 100,
sort_by = sort.gitlab.mentions,
format = format.gitlab.mentions,
},
merge_requests = {
limit = 100,
state = "opened", -- opened, closed, locked, merged
sort_by = sort.gitlab.merge_requests,
format = format.gitlab.merge_requests,
},
},
gitea = {
hosts = {}, -- list of private instances of gitea, with the port and the path prefix if any, such as "example.com/gitea"
issues = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.gitea.issues,
format = format.gitea.issues,
},
mentions = {
limit = 100,
sort_by = sort.gitea.mentions,
format = format.gitea.mentions,
},
pull_requests = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.gitea.pull_requests,
format = format.gitea.pull_requests,
},
},
forgejo = {
hosts = {}, -- list of private instances of forgejo, with the port and the path prefix if any
issues = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.forgejo.issues,
format = format.forgejo.issues,
},
mentions = {
limit = 100,
sort_by = sort.forgejo.mentions,
format = format.forgejo.mentions,
},
pull_requests = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.forgejo.pull_requests,
format = format.forgejo.pull_requests,
},
},
trigger_actions = {
{
pattern = [[^[[:alnum:]-]\+]],
actions = { "git_trailer_keys" },
},
{
pattern = [[^[[:alnum:]-]\+:\s*\zs\%([^[:space:]<>:#@!][^<>:#@!]*\%(<[^>]*\)\?\)\?]],
keyword_pattern = [[^[[:alnum:]-]\+\zs:\S*\|^[[:alnum:]-]\+:\s*\zs\%([^[:space:]<>:#@!][^<>:#@!]*\%(<[^>]*\)\?\)\?]],
actions = { "git_trailer_identities", "git_trailer_values" },
},
{
trigger_character = ":",
actions = { "git_commits" },
},
{
trigger_character = "#",
actions = {
"gitlab_issues",
"github_issues_and_change_requests",
"gitea_issues_and_change_requests",
"forgejo_issues_and_change_requests",
},
},
{
trigger_character = "@",
actions = { "gitlab_mentions", "github_mentions", "gitea_mentions", "forgejo_mentions" },
},
{
trigger_character = "!",
actions = { "gitlab_change_requests", "gitea_change_requests", "forgejo_change_requests" },
},
},
}
)docs/configuration.md describes these topics:
- Trigger actions
- Trailer completion
- Format and sort items
- Filetypes
- Remotes and SSH aliases
- CLIs, tokens, and curl
- Hosted instances
- Cache, and the
:CmpGitClearCachecommand - Troubleshooting
See CONTRIBUTING.md for the development setup, the tests, and the CI checks.
Special thanks to tjdevries for their informative video and starting code.