Cara Install LSP & Autocomplete (lspconfig + cmp) - Neovim

whynwd

whynwd Kamis, 07 Juli 2022

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.

Cara Install LSP & Autocomplete (lspconfig + cmp) - Neovim

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:

Cara Install LSP & Autocomplete (lspconfig + cmp) - Neovim

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.

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel