Today we’re going to finish our series here on the blog.
If you haven’t seen the previous chapters, follow the links:
And in this article we’ll install and configure:
/home/user/file
) when we start typing;<Tab>
;
Right away we’ll add all the plugins and then we’ll create the configuration files because they’ll all be nested.
Add these lines to your ~/.config/nvim/lua/plugins/plugins.lua
:
use 'neovim/nvim-lspconfig'
use 'hrsh7th/nvim-cmp'
use 'hrsh7th/cmp-nvim-lsp'
use 'hrsh7th/cmp-buffer'
use 'hrsh7th/cmp-path'
use 'hrsh7th/cmp-cmdline'
use 'saadparwaiz1/cmp_luasnip'
use 'L3MON4D3/LuaSnip'
use 'rafamadriz/friendly-snippets'
use 'ray-x/lsp_signature.nvim'
use {'tzachar/cmp-tabnine', run='./install.sh', requires = 'hrsh7th/nvim-cmp'}
use 'onsails/lspkind-nvim'
Note that tabnine will run a sh script as soon as it is added and has nvim-cmp as a dependency.
And then run: :PackerInstall
.
Now let’s create another file in : ~/.config/nvim/lua/plugins/tabnine.lua
and add the code for Machine Learning:
location has_any_words_before = function()
if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then
return false
end
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
end
require'lspconfig'.clangd.setup{}
require "lsp_signature".setup()
vim.o.completeopt = 'menuone,noselect'
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
cmp location = require'cmp'
location luasnip = require("luasnip")
cmp.setup({
mapping = {
['<C-n>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
['<C-p>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
['<Down>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
['<Up>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.close(),
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
['<Tab>'] = function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-expand-or-jump', true, true, true), '')
else
fallback()
end
end,
['<S-Tab>'] = function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-jump-prev', true, true, true), '')
else
fallback()
end
end,
},
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
sources = {
{ name = 'cmp_tabnine' },
{ name = 'luasnip' },
{ name = 'path' },
},
})
tabnine location = require('cmp_tabnine.config')
tabnine:setup({
max_lines = 1000;
max_num_results = 20;
sort = true;
run_on_every_keystroke = true;
snippet_placeholder = '..';
})
require('lspkind').init({
with_text = true,
preset = 'codicons',
symbol_map = {
Text = "",
Method = "",
Function = "",
Constructor = "",
Field = "ﰠ",
Variable = "",
Class = "ﴯ",
Interface = "",
Module = "",
Property = "ﰠ",
Unit = "塞",
Value = "",
Enum = "",
Keyword = "",
Snippet = "",
Color = "",
File = "",
Reference = "",
Folder = "",
EnumMember = "",
Constant = "",
Struct = "פּ",
Event = "",
Operator = "",
TypeParameter = ""
},
})
require("luasnip/loaders/from_vscode").load()
lspkind location = require('lspkind')
source_mapping location = {
buffer = "◉ Buffer",
nvim_lsp = "👐 LSP",
nvim_lua = "🌙 Lua",
cmp_tabnine = "💡 Tabnine",
path = "🚧 Path",
luasnip = "🌜 LuaSnip"
}
require'cmp'.setup {
sources = {
{ name = 'cmp_tabnine' },
{ name = 'luasnip' },
{ name = 'path' }
},
formatting = {
format = function(entry, vim_item)
vim_item.kind = lspkind.presets.default[vim_item.kind]
local menu = source_mapping[entry.source.name]
if entry.source.name == 'cmp_tabnine' then
if entry.completion_item.data ~= nil and entry.completion_item.data.detail ~= nil then
menu = entry.completion_item.data.detail .. ' ' .. menu
end
vim_item.kind = ''
end
vim_item.menu = menu
return vim_item
end
},
}
Do NOT add it to your init.lua
yet, as we are going to create a condition.
Let’s create another file(~/.config/nvim/lua/plugins/lsp.lua
) with similar code (you might think there will be duplicate code, but we are using all local variables and the file will only load accordingly with the later file we are going to create), but for the LSP:
location has_any_words_before = function()
if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then
return false
end
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
end
require'lspconfig'.clangd.setup{}
require "lsp_signature".setup()
vim.o.completeopt = 'menuone,noselect'
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
cmp location = require'cmp'
local luasnip = require("luasnip")
local lspkind = require('lspkind')
source_mapping location = {
buffer = "◉ Buffer",
nvim_lsp = "👐 LSP",
nvim_lua = "🌙 Lua",
cmp_tabnine = "💡 Tabnine",
path = "🚧 Path",
luasnip = "🌜 LuaSnip"
}
cmp.setup({
sources = {
{ name = 'nvim_lsp' },
{ name = 'luasnip' },
{ name = 'buffer' },
{ name = 'path' },
{ name = 'nvim_lua' },
},
formatting = {
format = function(entry, vim_item)
vim_item.kind = lspkind.presets.default[vim_item.kind]
local menu = source_mapping[entry.source.name]
if entry.source.name == 'cmp_tabnine' then
if entry.completion_item.data ~= nil and entry.completion_item.data.detail ~= nil then
menu = entry.completion_item.data.detail .. ' ' .. menu
end
vim_item.kind = ''
end
vim_item.menu = menu
return vim_item
end
},
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
mapping = {
['<C-n>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
['<C-p>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
['<Down>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
['<Up>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.close(),
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
['<Tab>'] = function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-expand-or-jump', true, true, true), '')
else
fallback()
end
end,
['<S-Tab>'] = function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-jump-prev', true, true, true), '')
else
fallback()
end
end,
},
})
require("luasnip/loaders/from_vscode").load()
There are a few details to make everyone work normally. tabnine is interesting to run when there is no LSP available, I usually include it in Markdown files because it’s easier, as when I’m writing code, it can mess up your LSP.
So, to separate let’s do the following, let’s create a file inside lua/plugins
named complete.lua
and insert the following content:
vim ~/.config/nvim/lua/plugins/complete.lua
if extension == "md" then
require("plugins.tabnine")
else
require("plugins.lsp")
end
And to load this new file, import into your init.lua
:
require("plugins.complete")
Now just test!
See below some videos/gif/image of the plugins we installed: