__
/ /________ _________ _____ _____ _
/ / ___/ __ \/ ___/ __ `/ __ `/ __ `/
/ (__ ) /_/ (__ ) /_/ / /_/ / /_/ /
/_/____/ .___/____/\__,_/\__, /\__,_/
/_/ /____/
⚡ 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,
})
Example config
local keymap = vim.keymap.set
local saga = require('lspsaga')
saga.init_lsp_saga()
-- Lsp finder find the symbol definition implmement reference
keymap("n", "gh", "<cmd>Lspsaga lsp_finder<CR>", { silent = true })
-- Code action
keymap("n", "<leader>ca", "<cmd>Lspsaga code_action<CR>", { silent = true })
keymap("v", "<leader>ca", "<cmd><C-U>Lspsaga range_code_action<CR>", { silent = true })
-- Rename
keymap("n", "gr", "<cmd>Lspsaga rename<CR>", { silent = true })
-- Definition preview
keymap("n", "gd", "<cmd>Lspsaga preview_definition<CR>", { silent = true })
-- Show line diagnostics
keymap("n", "<leader>cd", "<cmd>Lspsaga show_line_diagnostics<CR>", { silent = true })
-- Show cursor diagnostic
keymap("n", "<leader>cd", "<cmd>Lspsaga show_cursor_diagnostics<CR>", { silent = true })
-- Diagnsotic jump
keymap("n", "[e", "<cmd>Lspsaga diagnostic_jump_next<CR>", { silent = true })
keymap("n", "]e", "<cmd>Lspsaga diagnostic_jump_prev<CR>", { silent = true })
-- Only jump to error
keymap("n", "[E", function()
require("lspsaga.diagnostic").goto_prev({ severity = vim.diagnostic.severity.ERROR })
end, { silent = true })
keymap("n", "]E", function()
require("lspsaga.diagnostic").goto_next({ severity = vim.diagnostic.severity.ERROR })
end, { silent = true })
-- Outline
keymap("n","<leader>o", "<cmd>LSoutlineToggle<CR>",{ silent = true })
-- Hover Doc
keymap("n", "K", "<cmd>Lspsaga hover_doc<CR>", { silent = true })
-- Signature help
keymap("n", "gs", "<Cmd>Lspsaga signature_help<CR>", { silent = true })
local action = require("lspsaga.action")
-- scroll in hover doc or definition preview window
vim.keymap.set("n", "<C-f>", function()
action.smart_scroll_with_saga(1)
end, { silent = true })
-- scroll in hover doc or definition preview window
vim.keymap.set("n", "<C-b>", function()
action.smart_scroll_with_saga(-1)
end, { silent = true })
Default options with value
-- 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,
},
-- custom lsp kind
-- usage { Field = 'color code'} or {Field = {your icon, your color code}}
custom_kind = {},
-- 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/statusline
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_or_statusline()
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
-- if work in statusline
vim.wo.stl = win_val
end
end
local events = { 'BufEnter', 'BufWinEnter', 'CursorMoved' }
vim.api.nvim_create_autocmd(events, {
pattern = '*',
callback = function() config_winbar_or_statusline() end,
})
vim.api.nvim_create_autocmd('User', {
pattern = 'LspsagaUpdateSymbol',
callback = function() config_winbar_or_statusline() 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
}
you can use the custom_kind
option to change the default icon and color
-- if only change the color you can do it like
custom_kind = {
Field = '#000000',
}
-- if you want to change the icon and color
custom_kind = {
Field = {'your icon','your color'},
}
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 +
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.
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.