Language Server Protocol (LSP) adalah suatu protokol yang diciptakan untuk standardisasi berbagai macam protokol berbeda yang digunakan di setiap server bahasa pemograman. Satu protokol untuk mendukung integrasi server bahasa yang berbeda.
Dalam penggunaannya, LSP menghubungkan dan menginstegrasikan antara kode editor dengan server bahasa agar fitur-fitur yang ada pada server bahasa dapat digunakan pada editor kita, seperti Autocomplete, pemformatan otomatis, referensi, navigasi, pencarian, dan lain sebagainya.
LSP di Neovim
Neovim sendiri mendukung penggunaan LSP ini, dan kita dapat menggunakan fitur-fitur yang telah disebutkan diatas. Namun, untuk dapat menggunakan fitur-fitur tersebut, kita perlu menginstal dan mengkonfigurasi server LSP sendiri sesuai bahasa yang ingin digunakan.
Plugin
Dalam pembuatan konfigurasinya, terdapat plugin yang mendukung atau menyediakan konfigurasi LSP ini, yaitu nvim-lspconfig. Kita bisa gunakan lspconfig untuk membuat konfigurasi dan pengaturan server lebih mudah.
Namun, lspconfig yang kita install, tidak termasuk server klien bahasa. Lspconfig hanya membantu kita untuk dapat berkomunikasi dengan server bahasa. Jadi, server klien di install secara terpisah, baik secara manual maupun otomatis.
Sama halnya dengan Autocomplete. Karena Neovim tidak menyediakan autocomplete bawaan, kita juga perlu menginstall plugin untuk dapat mengimplementasikan fitur autocomplete ini.
Ada banyak plugin autocomplete yang bisa kita gunakan. Namun dalam pembahasan ini, plugin yang akan kita gunakan untuk autocomplete adalah nvm-cmp.
Berikut adalah plugin yang akan kita gunakan. Silakan klik untuk membuka repo dan melihat dokumentasi yang ada.
Sebelum Menginstal Plugin
Disini akan dijalaskan tentang langkah-langkah instalasi dan konfigurasi LSP dan Autocomplete di Neovim. Namun, sebelum ke proses instalasi, mungkin perlu dilakukan penyesuaian.
Jika saat ini sudah memiliki Neovim / Vim dengan pengaturan atau konfigurasi sendiri, kiranya dapat menyesuaikan, seperti struktur file konfigurasi dan package manager yang digunakan.
Untuk struktur file dan pengaturan konfigurasi dasar vim (neovim) yang digunakan dalam contoh pembahasan ini adalah dari repo nvim-windows dengan package manager Packer.nvim.
Jika ingin menggunakan vim dengan konfigurasi yang sama untuk percobaan, silakan buka atau kloning nvim-windows.
Instalasi dan Konfigurasi
Sekarang kita masuk ke proses instalasi plugin dan konfigurasi yang dibutuhan dalam penggunaan LSP dan Autocomplete di Neovim.
Langkah pertama kita adalah menginstal plugin. Sekali lagi, jika tidak menggunakan package manager Packer.nvim dan struktur file konfigurasi berbeda, silakan menyesuaikan.
Pada file plugins.lua, kita tambahkan daftar konfigurasi plugin bawah ini. Kita akan install nvim-lspconfig, nvim-cmp, dan plugin pendukung.
//lua/plugins.lua -- lsp use 'neovim/nvim-lspconfig' --cmp use { 'hrsh7th/nvim-cmp', requires = { 'hrsh7th/cmp-nvim-lsp', { "L3MON4D3/LuaSnip", requires = { "rafamadriz/friendly-snippets" }, config = function() require("luasnip.loaders.from_vscode").lazy_load() end, }, { 'hrsh7th/cmp-buffer', after = 'nvim-cmp' }, { 'hrsh7th/cmp-path', after = 'nvim-cmp' }, { 'saadparwaiz1/cmp_luasnip', after = 'nvim-cmp' }, }, config = [[require('config.cmp')]], event = 'InsertEnter *', } use { 'onsails/lspkind-nvim', config = function() require("lspkind").init() end, } use 'ray-x/lsp_signature.nvim'
Setelah di tambahkan, selanjutnya langsung kita lakukan penginstalan. Buka / restart vim dan install.
:PackerInstall
Setelah proses instalasi plugin selesai. Langkah selanjutnya, kita buat file baru dengan nama lsp.lua
pada direktori plugin, lalu copas konfigurasi di bawah ini.
//plugin/lsp.lua local lspconfig_ok, lspconfig = pcall(require, "lspconfig") if not lspconfig_ok then return end local lsp_signature_ok, lsp_signature = pcall(require, "lsp_signature") if not lsp_signature_ok then return end local cwd = vim.loop.cwd local on_attach = function(client, bufnr) lsp_signature.on_attach({ bind = true, floating_window = false, handler_opts = { border = "single" } }, bufnr) -- Enable completion triggered by <c-x><c-o> vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') -- Mappings. -- See `:help vim.lsp.*` for documentation on any of the below functions local bufopts = { noremap=true, silent=true, buffer=bufnr } vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts) vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts) vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts) vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts) vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts) vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder, bufopts) vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, bufopts) vim.keymap.set('n', '<space>wl', function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end, bufopts) vim.keymap.set('n', '<space>D', vim.lsp.buf.type_definition, bufopts) vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, bufopts) vim.keymap.set('n', '<space>ca', vim.lsp.buf.code_action, bufopts) vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts) vim.keymap.set('n', '<space>f', vim.lsp.buf.formatting, bufopts) end vim.lsp.handlers['textDocument/publishDiagnostics'] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { underline = false, virtual_text = { prefix = '', indent = 2, format = function(diagnostic) return string.format('// %s', diagnostic.message) end, }, signs = true, severity_sort = true, }) vim.lsp.handlers["textDocument/hover"] = vim.lsp.with( vim.lsp.handlers.hover, { border = "single" } ) local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities.textDocument.completion.completionItem.snippetSupport = true capabilities.textDocument.completion.completionItem.resolveSupport = { properties = { "documentation", "detail", "additionalTextEdits", }, } capabilities = require("cmp_nvim_lsp").update_capabilities(capabilities) lspconfig.tsserver.setup({ on_attach = on_attach, capabilities = capabilities, root_dir = cwd, }) lspconfig.html.setup({ on_attach = on_attach, capabilities = capabilities, root_dir = cwd, })
Kemudian pada direktori config, kita buat file baru dengan nama cmp.lua
dan copas kofigurasi di bawah ini.
//lua/config/cmp.lua local cmp_ok, cmp = pcall(require, 'cmp') if not cmp_ok then return end local snip_ok, luasnip = pcall(require, 'luasnip') if not snip_ok then return end local lspkind_ok, lspkind = pcall(require, 'lspkind') if not lspkind_ok then return end cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end }, formatting = { format = lspkind.cmp_format({ mode = 'symbol_text', }) }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, mapping = cmp.mapping.preset.insert({ ['<C-b>'] = cmp.mapping.scroll_docs(-4), ['<C-f>'] = cmp.mapping.scroll_docs(4), ['<C-Space>'] = cmp.mapping.complete(), ['<C-e>'] = cmp.mapping.abort(), ['<CR>'] = cmp.mapping.confirm({ select = false }), ["<Tab>"] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() else fallback() end end, { "i", "s" }), ["<S-Tab>"] = cmp.mapping(function() if cmp.visible() then cmp.select_prev_item() end end, { "i", "s" }), }), sources = cmp.config.sources({ { name = 'nvim_lsp_signature_help' }, { name = 'nvim_lsp' }, { name = 'luasnip' }, { name = 'path' }, },{ { name = 'buffer'}, }), })
Setelah pengaturan konfigurasi diatas dibuat, selanjutnya buka / muat ulang vim dan lakukan compiling.
:PackerCompile
Server Bahasa
Terakhir, kita lakukan penginstalan server bahasa. Pada konfigurasi lsp diatas, hanya 2 server yang di tambahkan untuk contoh, yaitu tsserver
(typescript) dan html
. Jadi, saat ini kita install 2 server tersebut:
//tsserver npm install -g typescript typescript-language-server //html npm i -g vscode-langservers-extracted
Jika ingin menginstall server lainnya, silakan buka server_configurations untuk melihat daftar server, dokumentasi, dan konfigurasi yang ada.
Untuk konfigurasi server baru, tinggal buat salinan konfigurasi lspconfig.[nama-server].setup({})
pada file lsp.lua, yang seperti di bawah ini.
//lsp.lua lspconfig.tsserver.setup({ on_attach = on_attach, capabilities = capabilities, root_dir = cwd, })
Setelah server bahasa selesai diinstall, sampai disini tinggal mencobanya. Silakah coba untuk membuka file javascript / typescript dan html untuk mencoba autocomplete yang telah dipasang.
Berikut adalah gambar contoh dari autocomplete dengan konfigurasi diatas:
Contoh lain dari LSP dan Autocomplete dengan dukungan beberaba server bahasa, dan contoh API diagnostic yang menampilkan kesalahan atau peringatan, bisa dilihat pada demo: Youtube.
Selesai
Silakan browsing atau buka repo github untuk setiap plugin yang telah diinstall untuk mencari tau apa fungsi atau kegunaannya, karena tidak dibahas disini. Begitu juga dengan keymap
pada file lsp.lua, silakan coba satu persatu.
Pembahasan tentang cara instalasi dan konfigurasi LSP dan Autocomplete di neovim selesai sampai disini. Silakan dicoba dan lakukan eksperimen.