__
/ /________ _________ _____ _____ _
/ / ___/ __ \/ ___/ __ `/ __ `/ __ `/
/ (__ ) /_/ (__ ) /_/ / /_/ / /_/ /
/_/____/ .___/____/\__,_/\__, /\__,_/
/_/ /____/
⚡ designed for convenience and efficiency ⚡
A light-weight lsp plugin based on neovim's built-in lsp with a highly performant UI.
Plug 'neovim/nvim-lspconfig'
Plug 'glepnir/lspsaga.nvim', { 'branch': 'main' }
use({
"glepnir/lspsaga.nvim",
branch = "main",
config = function()
local saga = require("lspsaga")
saga.init_lsp_saga({
-- your configuration
})
end,
})
Lspsaga support use command Lspsaga
with completion or use lua function
local saga = require 'lspsaga'
-- change the lsp symbol kind
local kind = require('lspsaga.lspkind')
kind[type_number][2] = icon -- see lua/lspsaga/lspkind.lua
-- use default config
saga.init_lsp_saga()
-- use custom config
saga.init_lsp_saga({
-- put modified options in there
})
-- Options with default value
-- "single" | "double" | "rounded" | "bold" | "plus"
border_style = "single",
--the range of 0 for fully opaque window (disabled) to 100 for fully
--transparent background. Values between 0-30 are typically most useful.
saga_winblend = 0,
-- when cursor in saga window you config these to move
move_in_saga = { prev = '<C-p>',next = '<C-n>'},
-- Error, Warn, Info, Hint
-- use emoji like
-- { "🙀", "😿", "😾", "😺" }
-- or
-- { "😡", "😥", "😤", "😐" }
-- and diagnostic_header can be a function type
-- must return a string and when diagnostic_header
-- is function type it will have a param `entry`
-- entry is a table type has these filed
-- { bufnr, code, col, end_col, end_lnum, lnum, message, severity, source }
diagnostic_header = { " ", " ", " ", "ﴞ " },
-- show diagnostic source
show_diagnostic_source = true,
-- add bracket or something with diagnostic source, just have 2 elements
diagnostic_source_bracket = {},
-- preview lines of lsp_finder and definition preview
max_preview_lines = 10,
-- use emoji lightbulb in default
code_action_icon = "💡",
-- if true can press number to execute the codeaction in codeaction window
code_action_num_shortcut = true,
-- same as nvim-lightbulb but async
code_action_lightbulb = {
enable = true,
sign = true,
enable_in_insert = true,
sign_priority = 20,
virtual_text = true,
},
-- finder icons
finder_icons = {
def = ' ',
ref = '諭 ',
link = ' ',
},
-- finder do lsp request timeout
-- if your project big enough or your server very slow
-- you may need to increase this value
finder_request_timeout = 1500,
finder_action_keys = {
open = "o",
vsplit = "s",
split = "i",
tabe = "t",
quit = "q",
scroll_down = "<C-f>",
scroll_up = "<C-b>", -- quit can be a table
},
code_action_keys = {
quit = "q",
exec = "<CR>",
},
rename_action_quit = "<C-c>",
rename_in_select = true,
definition_preview_icon = " ",
-- show symbols in winbar must nightly
symbol_in_winbar = {
in_custom = false,
enable = false,
separator = ' ',
show_file = true,
click_support = false,
},
-- show outline
show_outline = {
win_position = 'right',
--set special filetype win that outline window split.like NvimTree neotree
-- defx, db_ui
win_with = '',
win_width = 30,
auto_enter = true,
auto_preview = true,
virt_text = '┃',
jump_key = 'o',
-- auto refresh when change buffer
auto_refresh = true,
},
-- if you don't use nvim-lspconfig you must pass your server name and
-- the related filetypes into this table
-- like server_filetype_map = { metals = { "sbt", "scala" } }
server_filetype_map = {},
work with custom winbar
saga.init_lsp_saga({
symbol_in_winbar = {
in_custom = true
}
})
- use
require('lspsaga.symbolwinbar').get_symbol_node
this function in your custom winbar to get symbols node and setUser LspsagaUpdateSymbol
event in your autocmds
-- Example:
local function get_file_name(include_path)
local file_name = require('lspsaga.symbolwinbar').get_file_name()
if vim.fn.bufname '%' == '' then return '' end
if include_path == false then return file_name end
-- Else if include path: ./lsp/saga.lua -> lsp > saga.lua
local sep = vim.loop.os_uname().sysname == 'Windows' and '\\' or '/'
local path_list = vim.split(string.gsub(vim.fn.expand '%:~:.:h', '%%', ''), sep)
local file_path = ''
for _, cur in ipairs(path_list) do
file_path = (cur == '.' or cur == '~') and '' or
file_path .. cur .. ' ' .. '%#LspSagaWinbarSep#>%*' .. ' %*'
end
return file_path .. file_name
end
local function config_winbar()
local exclude = {
['teminal'] = true,
['toggleterm'] = true,
['prompt'] = true,
['NvimTree'] = true,
['help'] = true,
} -- Ignore float windows and exclude filetype
if vim.api.nvim_win_get_config(0).zindex or exclude[vim.bo.filetype] then
vim.wo.winbar = ''
else
local ok, lspsaga = pcall(require, 'lspsaga.symbolwinbar')
local sym
if ok then sym = lspsaga.get_symbol_node() end
local win_val = ''
win_val = get_file_name(true) -- set to true to include path
if sym ~= nil then win_val = win_val .. sym end
vim.wo.winbar = win_val
end
end
local events = { 'BufEnter', 'BufWinEnter', 'CursorMoved' }
vim.api.nvim_create_autocmd(events, {
pattern = '*',
callback = function() config_winbar() end,
})
vim.api.nvim_create_autocmd('User', {
pattern = 'LspsagaUpdateSymbol',
callback = function() config_winbar() end,
})
Support Click in symbols winbar
To enable click support for winbar define a function similar to statusline (Search for "Start of execute function label")
minwid will be replaced with current node. For example:
symbol_in_winbar = {
click_support = function(node, clicks, button, modifiers)
-- To see all avaiable details: vim.pretty_print(node)
local st = node.range.start
local en = node.range['end']
if button == "l" then
if clicks == 2 then
-- double left click to do nothing
else -- jump to node's starting line+char
vim.fn.cursor(st.line + 1, st.character + 1)
end
elseif button == "r" then
if modifiers == "s" then
print "lspsaga" -- shift right click to print "lspsaga"
end -- jump to node's ending line+char
vim.fn.cursor(en.line + 1, en.character + 1)
elseif button == "m" then
-- middle click to visual select node
vim.fn.cursor(st.line + 1, st.character + 1)
vim.cmd "normal v"
vim.fn.cursor(en.line + 1, en.character + 1)
end
end
}
Plugin does not provide mappings by default. However, you can bind mappings yourself. You can find examples in the showcase section.
Colors can be simply changed by overwriting the default highlights groups LspSaga is using.
highlight link LspSagaFinderSelection Search
" or
highlight link LspSagaFinderSelection guifg='#ff0000' guibg='#00ff00' gui='bold'
The available highlight groups you can find in here.
lsp finder
Finder Title work with neovim 0.8 +
Lua
-- or use command LspSagaFinder
vim.keymap.set("n", "gh", "<cmd>Lspsaga lsp_finder<CR>", { silent = true })
NOTE: This requires filetypes
and root_dir
set in the LSP server config
object. So for nvim-jdtls users, even if you are loading the plugin as ftplugin
or with FileType java
autocmd, set filetypes
in the config
object.
Code action
Lua
local action = require("lspsaga.codeaction")
-- code action
vim.keymap.set("n", "<leader>ca", action.code_action, { silent = true })
vim.keymap.set("v", "<leader>ca", function()
vim.fn.feedkeys(vim.api.nvim_replace_termcodes("<C-U>", true, false, true))
action.range_code_action()
end, { silent = true })
-- or use command
vim.keymap.set("n", "<leader>ca", "<cmd>Lspsaga code_action<CR>", { silent = true })
vim.keymap.set("v", "<leader>ca", "<cmd><C-U>Lspsaga range_code_action<CR>", { silent = true })
Hover doc
Lua
-- or use command
vim.keymap.set("n", "K", "<cmd>Lspsaga hover_doc<CR>", { silent = true })
local action = require("lspsaga.action")
-- scroll down hover doc or scroll in definition preview
vim.keymap.set("n", "<C-f>", function()
action.smart_scroll_with_saga(1)
end, { silent = true })
-- scroll up hover doc
vim.keymap.set("n", "<C-b>", function()
action.smart_scroll_with_saga(-1)
end, { silent = true })
Signature help
You also can use smart_scroll_with_saga
(see hover doc) to scroll in signature help win.
Lua
-- or command
vim.keymap.set("n", "gs", "<Cmd>Lspsaga signature_help<CR>", { silent = true })
Rename with preview and select
Lua
-- or command
vim.keymap.set("n", "gr", "<cmd>Lspsaga rename<CR>", { silent = true })
-- close rename win use <C-c> in insert mode or `q` in normal mode or `:q`
Preview definition
You also can use smart_scroll_with_saga
(see hover doc) to scroll in preview definition win.
Lua
-- or use command
vim.keymap.set("n", "gd", "<cmd>Lspsaga preview_definition<CR>", { silent = true })
Jump and show diagnostics
Lua
vim.keymap.set("n", "<leader>cd", "<cmd>Lspsaga show_line_diagnostics<CR>", { silent = true })
vim.keymap.set("n", "<leader>cd", "<cmd>Lspsaga show_cursor_diagnostics<CR>", { silent = true })
-- or jump to error
vim.keymap.set("n", "[E", function()
require("lspsaga.diagnostic").goto_prev({ severity = vim.diagnostic.severity.ERROR })
end, { silent = true })
vim.keymap.set("n", "]E", function()
require("lspsaga.diagnostic").goto_next({ severity = vim.diagnostic.severity.ERROR })
end, { silent = true })
-- or use command
vim.keymap.set("n", "[e", "<cmd>Lspsaga diagnostic_jump_next<CR>", { silent = true })
vim.keymap.set("n", "]e", "<cmd>Lspsaga diagnostic_jump_prev<CR>", { silent = true })
Outline
work fast when lspsaga symbol winbar in_custom = true
or enable = true
,
Lua
:LSoutlineToggle
Float terminal
Lua
-- float terminal also you can pass the cli command in open_float_terminal function
local term = require("lspsaga.floaterm")
-- float terminal also you can pass the cli command in open_float_terminal function
vim.keymap.set("n", "<A-d>", function()
term.open_float_terminal("custom_cli_command")
end, { silent = true })
vim.keymap.set("t", "<A-d>", function()
vim.fn.feedkeys(vim.api.nvim_replace_termcodes("<C-\\><C-n>", true, false, true))
term.close_float_terminal()
end, { silent = true })
-- or use command
vim.keymap.set("n", "<A-d>", "<cmd>Lspsaga open_floaterm custom_cli_command<CR>", { silent = true })
vim.keymap.set("t", "<A-d>", "<C-\\><C-n><cmd>Lspsaga close_floaterm<CR>", { silent = true })
If you'd like to support my work financially, buy me a drink through paypal.
Licensed under the MIT license.