forked from Archives/navigator.lua
init commit
parent
b080fa4010
commit
9d5f2efdbd
@ -0,0 +1,88 @@
|
||||
# Navigator
|
||||
|
||||
GUI for neovim lsp with a collection of most used LSP/treesitter functions.
|
||||
Easy code navigation. Based on LSP.
|
||||
|
||||
# Features:
|
||||
|
||||
- LSP easy setup. Support some of the most commonly used lsp client setup
|
||||
- GUI
|
||||
- fzy search
|
||||
- Better navigation for diagnostic errors, Navigate through files that contain errors/warnings
|
||||
- Group references/implementation/incomming/outgoing based on file names.
|
||||
|
||||
# Why a new plugin
|
||||
|
||||
After installed a handful of lsp plugins, I still got ~500 loc for lsp and still increasing. Reason is that I need
|
||||
to tune the plugins to fit my requirements.
|
||||
|
||||
# Similar projects / special mentions:
|
||||
|
||||
- [nvim-lsputils](https://github.com/RishabhRD/nvim-lsputils)
|
||||
- [nvim-fzy](https://github.com/mfussenegger/nvim-fzy.git)
|
||||
- [fuzzy](https://github.com/amirrezaask/fuzzy.nvim)
|
||||
- [lspsaga](https://github.com/glepnir/lspsaga.nvim)
|
||||
|
||||
# Install
|
||||
|
||||
You can remove your lspconfig setup and use this plugin.
|
||||
The plugin depends on [guihua.lua](https://github.com/ray-x/guihua.lua), which provides gui and fzy support.
|
||||
|
||||
```vim
|
||||
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
|
||||
Plug 'ray-x/navigator.lua'
|
||||
```
|
||||
|
||||
Packer
|
||||
|
||||
```lua
|
||||
|
||||
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}}
|
||||
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```lua
|
||||
lua require'navigator'.setup()
|
||||
```
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Reference
|
||||
|
||||
![reference](https://github.com/ray-x/files/blob/master/img/navigator/ref.gif?raw=true)
|
||||
|
||||
### Diagnostic
|
||||
|
||||
![diagnostic](https://github.com/ray-x/files/blob/master/img/navigator/diag.jpg?raw=true)
|
||||
|
||||
### Implementation
|
||||
|
||||
![implementation](https://github.com/ray-x/files/blob/master/img/navigator/implemention.jpg?raw=true)
|
||||
|
||||
### Fzy search in reference
|
||||
|
||||
![fzy_reference](https://github.com/ray-x/files/blob/master/img/navigator/fzy_reference.jpg?raw=true)
|
||||
|
||||
### Code actions
|
||||
|
||||
![code actions](https://github.com/ray-x/files/blob/master/img/navigator/codeaction.jpg?raw=true)
|
||||
|
||||
### Code preview with highlight
|
||||
|
||||
![code preview](https://github.com/ray-x/files/blob/master/img/navigator/preview_with_hl.jpg?raw=true)
|
||||
|
||||
### Call hierarchy (incomming/outgoing)
|
||||
|
||||
![incomming](https://github.com/ray-x/files/blob/master/img/navigator/incomming.jpg?raw=true)
|
||||
|
||||
# Todo
|
||||
|
||||
- Early phase, bugs expected
|
||||
- Async (some of the requests is slow on large codebase and might be good to use co-rountine)
|
||||
- More clients. I use go, python, js/ts, java, c/cpp, lua most of the time. Do not test other languages (e.g rust, swift etc)
|
||||
|
||||
```
|
||||
|
||||
```
|
@ -0,0 +1 @@
|
||||
TODO.txt
|
@ -0,0 +1,52 @@
|
||||
local M = {}
|
||||
|
||||
M.config_values ={
|
||||
debug = false, -- log output
|
||||
code_action_icon = ' ',
|
||||
code_action_prompt = {
|
||||
enable = true,
|
||||
sign = true,
|
||||
sign_priority = 40,
|
||||
virtual_text = true,
|
||||
},
|
||||
}
|
||||
|
||||
vim.cmd("command! -nargs=0 LspLog call v:lua.open_lsp_log()")
|
||||
vim.cmd("command! -nargs=0 LspRestart call v:lua.reload_lsp()")
|
||||
|
||||
local extend_config = function(opts)
|
||||
opts = opts or {}
|
||||
if next(opts) == nil then return end
|
||||
for key,value in pairs(opts) do
|
||||
if M.config_values[key] == nil then
|
||||
error(string.format('[] Key %s not valid',key))
|
||||
return
|
||||
end
|
||||
if type(M.config_values[key]) == 'table' then
|
||||
for k,v in pairs(value) do
|
||||
M.config_values[key][k] = v
|
||||
end
|
||||
else
|
||||
M.config_values[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
M.setup = function(cfg)
|
||||
extend_config(cfg)
|
||||
-- print("loading navigator")
|
||||
require('navigator.lspclient').setup(M.config_values)
|
||||
require('navigator.reference')
|
||||
require('navigator.definition')
|
||||
require('navigator.hierarchy')
|
||||
require('navigator.implementation')
|
||||
|
||||
print("navigator loader")
|
||||
|
||||
if M.config_values.code_action_prompt.enable then
|
||||
vim.cmd [[autocmd CursorHold,CursorHoldI * lua require'navigator.codeAction'.code_action_prompt()]]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,209 @@
|
||||
local util = require "navigator.util"
|
||||
local log = util.log
|
||||
local code_action = {}
|
||||
local gui = require "navigator.gui"
|
||||
local config = require("navigator").config_values
|
||||
local api = vim.api
|
||||
function code_action.code_action_handler(err, _, actions, num, _, _, customSelectionHandler)
|
||||
-- log(actions)
|
||||
if actions == nil or vim.tbl_isempty(actions) then
|
||||
print("No code actions available")
|
||||
return
|
||||
end
|
||||
local data = {" Auto Fix <C-o> Apply <C-e> Exit"}
|
||||
for i, action in ipairs(actions) do
|
||||
local title = action.title:gsub("\r\n", "\\r\\n")
|
||||
title = title:gsub("\n", "\\n")
|
||||
title = string.format("[%d] %s", i, title)
|
||||
table.insert(data, title)
|
||||
end
|
||||
local width = 0
|
||||
for _, str in ipairs(data) do
|
||||
if #str > width then
|
||||
width = #str
|
||||
end
|
||||
end
|
||||
-- log(data)
|
||||
|
||||
local function apply_action(idx)
|
||||
local action_chosen = actions[idx - 1]
|
||||
if action_chosen.edit or type(action_chosen.command) == "table" then
|
||||
if action_chosen.edit then
|
||||
vim.lsp.util.apply_workspace_edit(action_chosen.edit)
|
||||
end
|
||||
if type(action_chosen.command) == "table" then
|
||||
vim.lsp.buf.execute_command(action_chosen.command)
|
||||
end
|
||||
else
|
||||
vim.lsp.buf.execute_command(action_chosen)
|
||||
end
|
||||
end
|
||||
|
||||
gui.new_list_view {
|
||||
items = data,
|
||||
width = width + 4,
|
||||
loc = "top_center",
|
||||
relative = "cursor",
|
||||
rawdata = true,
|
||||
data = data,
|
||||
on_confirm = function(pos)
|
||||
if pos < 2 then
|
||||
pos = 2
|
||||
end
|
||||
apply_action(pos)
|
||||
end,
|
||||
on_move = function(pos)
|
||||
if pos < 2 then
|
||||
pos = 2
|
||||
end
|
||||
local l = data[pos]
|
||||
-- log("on move", l)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
-- https://github.com/glepnir/lspsaga.nvim/blob/main/lua/lspsaga/codeaction.lua
|
||||
-- lspsaga has a clever design to inject code action indicator
|
||||
local sign_group = "nvcodeaction"
|
||||
local get_namespace = function()
|
||||
return api.nvim_create_namespace(sign_group)
|
||||
end
|
||||
|
||||
local get_current_winid = function()
|
||||
return api.nvim_get_current_win()
|
||||
end
|
||||
|
||||
local sign_name = "NavigatorLightBulb"
|
||||
|
||||
if vim.tbl_isempty(vim.fn.sign_getdefined(sign_name)) then
|
||||
vim.fn.sign_define(sign_name, {text = config.code_action_icon, texthl = "LspDiagnosticsSignHint"})
|
||||
end
|
||||
|
||||
local function _update_virtual_text(line)
|
||||
local namespace = get_namespace()
|
||||
api.nvim_buf_clear_namespace(0, namespace, 0, -1)
|
||||
|
||||
if line then
|
||||
local icon_with_indent = " " .. config.code_action_icon
|
||||
|
||||
-- log("updat text", line, icon_with_indent)
|
||||
api.nvim_buf_set_extmark(
|
||||
0,
|
||||
namespace,
|
||||
line,
|
||||
-1,
|
||||
{
|
||||
virt_text = {{icon_with_indent, "LspDiagnosticsSignHint"}},
|
||||
virt_text_pos = "overlay",
|
||||
hl_mode = "combine"
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local function _update_sign(line)
|
||||
local winid = get_current_winid()
|
||||
if code_action[winid] and code_action[winid].lightbulb_line ~= 0 then
|
||||
vim.fn.sign_unplace(sign_group, {id = code_action[winid].lightbulb_line, buffer = "%"})
|
||||
end
|
||||
|
||||
if line then
|
||||
--log("updatasign", line, sign_group, sign_name)
|
||||
vim.fn.sign_place(
|
||||
line,
|
||||
sign_group,
|
||||
sign_name,
|
||||
"%",
|
||||
{lnum = line + 1, priority = config.code_action_prompt.sign_priority}
|
||||
)
|
||||
code_action[winid].lightbulb_line = line
|
||||
end
|
||||
end
|
||||
|
||||
local need_check_diagnostic = {
|
||||
["go"] = true,
|
||||
["python"] = true
|
||||
}
|
||||
|
||||
function code_action:render_action_virtual_text(line, diagnostics)
|
||||
return function(_, _, actions)
|
||||
|
||||
if actions == nil or type(actions) ~= "table" or vim.tbl_isempty(actions) then
|
||||
if config.code_action_prompt.virtual_text then
|
||||
_update_virtual_text(nil)
|
||||
end
|
||||
if config.code_action_prompt.sign then
|
||||
_update_sign(nil)
|
||||
end
|
||||
else
|
||||
if config.code_action_prompt.sign then
|
||||
if need_check_diagnostic[vim.bo.filetype] then
|
||||
if next(diagnostics) == nil then
|
||||
_update_sign(nil)
|
||||
else
|
||||
_update_sign(line)
|
||||
end
|
||||
else
|
||||
_update_sign(line)
|
||||
end
|
||||
end
|
||||
|
||||
if config.code_action_prompt.virtual_text then
|
||||
if need_check_diagnostic[vim.bo.filetype] then
|
||||
if next(diagnostics) == nil then
|
||||
_update_virtual_text(nil)
|
||||
else
|
||||
_update_virtual_text(line)
|
||||
end
|
||||
else
|
||||
_update_virtual_text(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local special_buffers = {
|
||||
["LspSagaCodecode_action"] = true,
|
||||
["lspsagafinder"] = true,
|
||||
["NvimTree"] = true,
|
||||
["vist"] = true,
|
||||
["lspinfo"] = true,
|
||||
["markdown"] = true,
|
||||
["text"] = true
|
||||
}
|
||||
-- local action_call_back = function (_,_)
|
||||
-- return Action:action_callback()
|
||||
-- end
|
||||
|
||||
local action_vritual_call_back = function (line,diagnostics)
|
||||
return code_action:render_action_virtual_text(line,diagnostics)
|
||||
end
|
||||
|
||||
local code_action_req = function(_call_back_fn, diagnostics)
|
||||
local context = {diagnostics = diagnostics}
|
||||
local params = vim.lsp.util.make_range_params()
|
||||
params.context = context
|
||||
local line = params.range.start.line
|
||||
local callback = _call_back_fn(line, diagnostics)
|
||||
vim.lsp.buf_request(0, "textDocument/codeAction", params, callback)
|
||||
end
|
||||
|
||||
-- code_action.code_action = function()
|
||||
-- local diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
|
||||
-- code_action_req(action_call_back, diagnostics)
|
||||
-- end
|
||||
|
||||
code_action.code_action_prompt = function()
|
||||
if special_buffers[vim.bo.filetype] then
|
||||
return
|
||||
end
|
||||
|
||||
local diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
|
||||
local winid = get_current_winid()
|
||||
code_action[winid] = code_action[winid] or {}
|
||||
code_action[winid].lightbulb_line = code_action[winid].lightbulb_line or 0
|
||||
code_action_req(action_vritual_call_back, diagnostics)
|
||||
end
|
||||
|
||||
return code_action
|
@ -0,0 +1,101 @@
|
||||
local util = require "navigator.util"
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local locations_to_items = lsphelper.locations_to_items
|
||||
local gui = require "navigator.gui"
|
||||
local log = util.log
|
||||
local TextView = require("guihua.textview")
|
||||
-- callback for lsp definition, implementation and declaration handler
|
||||
local function definition_hdlr(_, _, locations, _, bufnr)
|
||||
-- log(locations)
|
||||
if locations == nil or vim.tbl_isempty(locations) then
|
||||
print "Definition not found"
|
||||
return
|
||||
end
|
||||
if vim.tbl_islist(locations) then
|
||||
if #locations > 1 then
|
||||
local items = locations_to_items(locations)
|
||||
gui.new_list_view({items = items, api = 'Definition'})
|
||||
else
|
||||
vim.lsp.util.jump_to_location(locations[1])
|
||||
end
|
||||
else
|
||||
vim.lsp.util.jump_to_location(locations)
|
||||
end
|
||||
end
|
||||
|
||||
local function def_preview(timeout_ms)
|
||||
local method = "textDocument/definition"
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 2000)
|
||||
|
||||
if result == nil or vim.tbl_isempty(result) then
|
||||
print("No result found: " .. method)
|
||||
return nil
|
||||
end
|
||||
|
||||
local data = {}
|
||||
-- result = {vim.tbl_deep_extend("force", {}, unpack(result))}
|
||||
-- log("def-preview", result)
|
||||
for key, value in pairs(result) do
|
||||
if result[key] ~= nil then
|
||||
table.insert(data, result[key].result[1])
|
||||
end
|
||||
end
|
||||
local range = data[1].targetRange or data[1].range
|
||||
|
||||
local row = range.start.line
|
||||
-- in case there are comments
|
||||
row = math.max(row - 3, 1)
|
||||
local delta = range.start.line - row + 1
|
||||
local uri = data[1].uri or data[1].targetUri
|
||||
if not uri then
|
||||
return
|
||||
end
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
if not vim.api.nvim_buf_is_loaded(bufnr) then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
|
||||
local definition = vim.api.nvim_buf_get_lines(bufnr, row, range["end"].line + 12, false)
|
||||
local def_line = vim.api.nvim_buf_get_lines(bufnr, range.start.line, range.start.line + 1, false)
|
||||
for _ = 1, math.min(3, #definition), 1 do
|
||||
if #definition[1] < 2 then
|
||||
table.remove(definition, 1)
|
||||
delta = delta - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
definition = vim.list_extend({" " .. "Definition: "}, definition)
|
||||
local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype")
|
||||
|
||||
-- TODO multiple resuts?
|
||||
local opts = {
|
||||
relative = "cursor",
|
||||
style = "minimal",
|
||||
ft = filetype,
|
||||
data = definition,
|
||||
enter = true
|
||||
}
|
||||
TextView:new(opts)
|
||||
delta = delta + 1 -- header
|
||||
local cmd = "normal! " .. tostring(delta) .. "G"
|
||||
|
||||
vim.cmd(cmd)
|
||||
vim.cmd('set cursorline')
|
||||
if #def_line > 0 then
|
||||
local niddle = require('guihua.util').add_escape(def_line[1])
|
||||
log(def_line[1], niddle)
|
||||
vim.fn.matchadd("Search", niddle)
|
||||
end
|
||||
-- TODO:
|
||||
-- https://github.com/oblitum/goyo.vim/blob/master/autoload/goyo.vim#L108-L135
|
||||
end
|
||||
|
||||
vim.lsp.handlers["textDocument/definition"] = definition_hdlr
|
||||
return {
|
||||
definition_handler = definition_hdlr,
|
||||
definition_preview = def_preview,
|
||||
declaration_handler = definition_hdlr,
|
||||
typeDefinition_handler = definition_hdlr
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
local gui = require "navigator.gui"
|
||||
local diagnostic_list = {}
|
||||
local log = require "navigator.util".log
|
||||
diagnostic_list[vim.bo.filetype] = {}
|
||||
|
||||
local diag_hdlr = function(err, method, result, client_id, br, config)
|
||||
-- log(result)
|
||||
vim.lsp.diagnostic.on_publish_diagnostics(err, method, result, client_id, br, config)
|
||||
if err ~= nil then log(err, config) end
|
||||
local cwd = vim.fn.getcwd(0)
|
||||
local ft = vim.bo.filetype
|
||||
if diagnostic_list[ft] == nil then
|
||||
diagnostic_list[vim.bo.filetype] = {}
|
||||
end
|
||||
-- vim.lsp.diagnostic.clear(vim.fn.bufnr(), client.id, nil, nil)
|
||||
|
||||
local uri = result.uri
|
||||
if result and result.diagnostics then
|
||||
local item_list = {}
|
||||
|
||||
for _, v in ipairs(result.diagnostics) do
|
||||
local item = v
|
||||
item.filename = assert(vim.uri_to_fname(uri))
|
||||
item.display_filename = item.filename:gsub(cwd .. "/", "./", 1)
|
||||
item.lnum = v.range.start.line + 1
|
||||
item.col = v.range.start.character + 1
|
||||
item.uri = uri
|
||||
local head = " "
|
||||
if v.severity > 1 then
|
||||
head = " "
|
||||
end
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
vim.fn.bufload(bufnr)
|
||||
local pos = v.range.start
|
||||
local row = pos.line
|
||||
local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1]
|
||||
item.text = head .. tostring(item.lnum) .. ": " .. line .. " " .. v.message
|
||||
table.insert(item_list, item)
|
||||
end
|
||||
-- local old_items = vim.fn.getqflist()
|
||||
diagnostic_list[ft][uri] = item_list
|
||||
end
|
||||
end
|
||||
|
||||
local M = {}
|
||||
-- vim.lsp.handlers["textDocument/publishDiagnostics"] =
|
||||
M.diagnostic_handler =
|
||||
vim.lsp.with(
|
||||
diag_hdlr,
|
||||
{
|
||||
-- Enable underline, use default values
|
||||
underline = true,
|
||||
-- Enable virtual text, override spacing to 0
|
||||
virtual_text = {
|
||||
spacing = 0,
|
||||
prefix = " " --' ,
|
||||
},
|
||||
-- Use a function to dynamically turn signs off
|
||||
-- and on, using buffer local variables
|
||||
signs = true,
|
||||
-- Disable a feature
|
||||
update_in_insert = false
|
||||
}
|
||||
)
|
||||
M.show_diagnostic = function()
|
||||
if diagnostic_list[vim.bo.filetype] ~= nil then
|
||||
log(diagnostic_list[vim.bo.filetype])
|
||||
-- vim.fn.setqflist({}, " ", {title = "LSP", items = diagnostic_list[vim.bo.filetype]})
|
||||
local results = diagnostic_list[vim.bo.filetype]
|
||||
local display_items = {}
|
||||
for _, items in pairs(results) do
|
||||
for _, it in pairs(items) do
|
||||
table.insert(display_items, it)
|
||||
end
|
||||
end
|
||||
log(display_items)
|
||||
if #display_items > 0 then
|
||||
gui.new_list_view({items = display_items, api = 'Diagnostic'})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,149 @@
|
||||
local M = {}
|
||||
local ListView = require "guihua.listview"
|
||||
local TextView = require "guihua.textview"
|
||||
local View = require "guihua.view"
|
||||
local util = require "navigator.util"
|
||||
local log = require "navigator.util".log
|
||||
|
||||
function M.new_preview(opts)
|
||||
return TextView:new(
|
||||
{
|
||||
loc = "top_center",
|
||||
rect = {
|
||||
height = #opts.items + 4,
|
||||
width = opts.width or 90,
|
||||
pos_x = opts.pos_x or 0,
|
||||
pos_y = opts.pos_y or 4
|
||||
},
|
||||
-- data = display_data,
|
||||
relative = opts.relative,
|
||||
data = opts.items,
|
||||
syntax = opts.syntax,
|
||||
enter = opts.enter or false
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
function M._preview_location(location, width, pos_x, pos_y)
|
||||
local api = vim.api
|
||||
local uri = location.targetUri or location.uri
|
||||
if uri == nil then
|
||||
log("invalid uri ", location)
|
||||
return
|
||||
end
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
if not api.nvim_buf_is_loaded(bufnr) then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
--
|
||||
local range = location.targetRange or location.range
|
||||
local contents = api.nvim_buf_get_lines(bufnr, range.start.line, range["end"].line + 1, false)
|
||||
--
|
||||
local syntax = api.nvim_buf_get_option(bufnr, "syntax")
|
||||
if syntax == nil or #syntax < 1 then
|
||||
syntax = api.nvim_buf_get_option(bufnr, "ft")
|
||||
end
|
||||
|
||||
log(syntax, contents)
|
||||
local opts = {syntax = syntax, width = width, pos_x = pos_x or 0, pos_y = pos_y or 10}
|
||||
opts.items = contents
|
||||
log("syntax", opts.syntax)
|
||||
return M.new_preview(opts)
|
||||
end
|
||||
|
||||
-- local bufnr, winnr =lsp.util.open_floating_preview(contents, syntax, {offset_x=30, offset_y=20})
|
||||
--
|
||||
-- vim.api.nvim_buf_set_var(bufnr, "lsp_floating", true)
|
||||
-- return bufnr, winnr
|
||||
--
|
||||
|
||||
function M.preview_file(filename, width, line, col, offset_x, offset_y)
|
||||
log("file", filename, line, offset_x, offset_y)
|
||||
if line >= 2 then
|
||||
line = line - 2
|
||||
end
|
||||
local loc = {uri = "file:///" .. filename, targetRange = {start = {line = line}}}
|
||||
offset_x = offset_x or 0
|
||||
offset_y = offset_y or 6
|
||||
loc.targetRange["end"] = {line = line + 4}
|
||||
return M._preview_location(loc, width, offset_x, offset_y)
|
||||
end
|
||||
|
||||
function M.preview_uri(uri, width, line, col, offset_x, offset_y)
|
||||
log("uri", uri, line, offset_x, offset_y)
|
||||
if line >= 2 then
|
||||
line = line - 2
|
||||
end
|
||||
offset_x = offset_x or 0
|
||||
offset_y = offset_y or 6
|
||||
local loc = {uri = uri, targetRange = {start = {line = line}}}
|
||||
loc.targetRange["end"] = {line = line + 4}
|
||||
return M._preview_location(loc, width, offset_x, offset_y)
|
||||
end
|
||||
|
||||
function M.new_list_view(opts)
|
||||
local items = opts.items
|
||||
local data = {}
|
||||
if opts.rawdata then
|
||||
data = items
|
||||
else
|
||||
data = require "guihua.util".aggregate_filename(items, opts)
|
||||
end
|
||||
local wwidth = vim.api.nvim_get_option("columns")
|
||||
local width = opts.width or math.floor(wwidth * 0.8)
|
||||
local wheight = math.floor(vim.api.nvim_get_option("lines") * 0.8)
|
||||
local prompt = opts.prompt or false
|
||||
if data and not vim.tbl_isempty(data) then
|
||||
-- replace
|
||||
if #data > 10 and opts.prompt == nil then
|
||||
prompt = true
|
||||
end
|
||||
|
||||
local height = math.min(#data, math.floor(wheight / 2))
|
||||
local offset_y = height
|
||||
if prompt then
|
||||
offset_y = offset_y + 1
|
||||
end
|
||||
return ListView:new(
|
||||
{
|
||||
loc = "top_center",
|
||||
prompt = prompt,
|
||||
relative = opts.relative,
|
||||
style = opts.style,
|
||||
api = opts.api,
|
||||
rect = {
|
||||
height = height,
|
||||
width = width,
|
||||
pos_x = 0,
|
||||
pos_y = 0
|
||||
},
|
||||
-- data = display_data,
|
||||
data = data,
|
||||
on_confirm = opts.on_confirm or function(pos)
|
||||
if pos == 0 then
|
||||
pos = 1
|
||||
end
|
||||
local l = data[pos]
|
||||
if l.filename ~= nil then
|
||||
util.open_file_at(l.filename, l.lnum)
|
||||
end
|
||||
end,
|
||||
on_move = opts.on_move or function(pos)
|
||||
if pos == 0 then
|
||||
pos = 1
|
||||
end
|
||||
local l = data[pos]
|
||||
log("on move", pos, l.text or l, l.uri, l.filename)
|
||||
-- todo fix
|
||||
if l.uri ~= nil then
|
||||
return M.preview_uri(l.uri, width, l.lnum, l.col, 0, offset_y)
|
||||
else
|
||||
return M.preview_file(l.filename, width, l.lnum, l.col, 0, offset_y)
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,85 @@
|
||||
local gui = require "navigator.gui"
|
||||
local util = require "navigator.util"
|
||||
local log = util.log
|
||||
local partial = util.partial
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local cwd = vim.fn.getcwd(0)
|
||||
local M = {}
|
||||
|
||||
local function call_hierarchy_handler(direction, err, _, result, _, _, error_message)
|
||||
-- log('call_hierarchy')
|
||||
if err ~= nil then
|
||||
print("ERROR: " .. error_message)
|
||||
return
|
||||
end
|
||||
|
||||
-- log("dir", direction, "result", result)
|
||||
local items = {}
|
||||
for _, call_hierarchy_call in pairs(result) do
|
||||
local call_hierarchy_item = call_hierarchy_call[direction]
|
||||
local kind = ' '
|
||||
if call_hierarchy_item.kind then
|
||||
kind = require'navigator.lspclient.lspkind'.kind(call_hierarchy_item.kind) .. ' '
|
||||
end
|
||||
for _, range in pairs(call_hierarchy_call.fromRanges) do
|
||||
local filename = assert(vim.uri_to_fname(call_hierarchy_item.uri))
|
||||
local display_filename = filename:gsub(cwd .. "/", "./", 1)
|
||||
table.insert(
|
||||
items,
|
||||
{
|
||||
uri = call_hierarchy_item.uri,
|
||||
filename = filename,
|
||||
-- display_filename = filename:gsub(cwd .. "/", "./", 1),
|
||||
display_filename = call_hierarchy_item.detail or display_filename,
|
||||
text = kind .. call_hierarchy_item.name,
|
||||
range = range,
|
||||
lnum = range.start.line,
|
||||
col = range.start.character
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
local call_hierarchy_handler_from = partial(call_hierarchy_handler, "from")
|
||||
local call_hierarchy_handler_to = partial(call_hierarchy_handler, "to")
|
||||
|
||||
local function incoming_calls_handler(bang, err, method, result, client_id, bufnr)
|
||||
local results = call_hierarchy_handler_from(err, method, result, client_id, bufnr, "Incoming calls not found")
|
||||
gui.new_list_view({items = results, api = 'incomming'})
|
||||
end
|
||||
|
||||
local function outgoing_calls_handler(bang, err, method, result, client_id, bufnr)
|
||||
local results = call_hierarchy_handler_to(err, method, result, client_id, bufnr, "Outgoing calls not found")
|
||||
|
||||
gui.new_list_view({items =results, api = 'outgoing'})
|
||||
--fzf_locations(bang, "", "Outgoing Calls", results, false)
|
||||
end
|
||||
|
||||
|
||||
function M.incoming_calls(bang, opts)
|
||||
if not lsphelper.check_capabilities("call_hierarchy") then
|
||||
return
|
||||
end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
util.call_sync("callHierarchy/incomingCalls", params, opts, partial(incoming_calls_handler, bang))
|
||||
end
|
||||
|
||||
function M.outgoing_calls(bang, opts)
|
||||
if not lsphelper.check_capabilities("call_hierarchy") then
|
||||
return
|
||||
end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
util.call_sync("callHierarchy/outgoingCalls", params, opts, partial(outgoing_calls_handler, bang))
|
||||
end
|
||||
|
||||
M.incoming_calls_call = partial(M.incoming_calls, 0)
|
||||
M.outgoing_calls_call = partial(M.outgoing_calls, 0)
|
||||
|
||||
M.incoming_calls_handler = partial(incoming_calls_handler, 0)
|
||||
M.outgoing_calls_handler = partial(outgoing_calls_handler, 0)
|
||||
|
||||
return M
|
@ -0,0 +1,23 @@
|
||||
-- TODO: change background and use TextView?
|
||||
local lsp = require("vim.lsp")
|
||||
return { hover_handler = function(_, method, result)
|
||||
vim.lsp.util.focusable_float(
|
||||
method,
|
||||
function()
|
||||
if not (result and result.contents) then
|
||||
return
|
||||
end
|
||||
local markdown_lines = lsp.util.convert_input_to_markdown_lines(result.contents)
|
||||
markdown_lines = lsp.util.trim_empty_lines(markdown_lines)
|
||||
if vim.tbl_isempty(markdown_lines) then
|
||||
return
|
||||
end
|
||||
|
||||
local bnr, contents_winid, _, border_winid = vim.lsp.util.fancy_floating_markdown(markdown_lines)
|
||||
lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, contents_winid)
|
||||
lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, border_winid)
|
||||
return bnr, contents_winid
|
||||
end
|
||||
)
|
||||
end
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
local util = require "navigator.util"
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local gui = require "navigator.gui"
|
||||
local M = {}
|
||||
local location = require("guihua.location")
|
||||
local partial = util.partial
|
||||
local locations_to_items = lsphelper.locations_to_items
|
||||
local log = util.log
|
||||
-- dataformat should be same as reference
|
||||
local function location_handler(err, _, locations, _, bufnr, error_message)
|
||||
if err ~= nil then
|
||||
print("ERROR: " .. tostring(err) .. error_message)
|
||||
return
|
||||
end
|
||||
return locations_to_items(locations)
|
||||
end
|
||||
|
||||
local function implementation_handler(bang, err, method, result, client_id, bufnr)
|
||||
local results = location_handler(err, method, result, client_id, bufnr, "Implementation not found")
|
||||
gui.new_list_view({items =results, api = 'Implementation'})
|
||||
end
|
||||
|
||||
function M.implementation(bang, opts)
|
||||
if not lsphelper.check_capabilities("implementation") then
|
||||
return
|
||||
end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
util.call_sync("textDocument/implementation", params, opts, partial(implementation_handler, bang))
|
||||
end
|
||||
|
||||
|
||||
|
||||
M.implementation_call = partial(M.implementation, 0)
|
||||
|
||||
M.implementation_handler = partial(implementation_handler, 0)
|
||||
|
||||
return M
|
@ -0,0 +1,74 @@
|
||||
local vim, api = vim, vim.api
|
||||
local lsp = require("vim.lsp")
|
||||
|
||||
local util = require "navigator.util"
|
||||
local log = util.log
|
||||
|
||||
if not packer_plugins["nvim-lua/lsp-status.nvim"] or not packer_plugins["lsp-status.nvim"].loaded then
|
||||
vim.cmd [[packadd lsp-status.nvim]]
|
||||
end
|
||||
local lsp_status = require("lsp-status")
|
||||
|
||||
local diagnostic_map = function(bufnr)
|
||||
local opts = {noremap = true, silent = true}
|
||||
api.nvim_buf_set_keymap(bufnr, "n", "]O", ":lua vim.lsp.diagnostic.set_loclist()<CR>", opts)
|
||||
end
|
||||
local M = {}
|
||||
local function documentHighlight()
|
||||
api.nvim_exec(
|
||||
[[
|
||||
hi LspReferenceRead cterm=bold gui=Bold ctermbg=yellow guibg=DarkOrchid3
|
||||
hi LspReferenceText cterm=bold gui=Bold ctermbg=red guibg=gray27
|
||||
hi LspReferenceWrite cterm=bold gui=Bold,Italic ctermbg=red guibg=MistyRose
|
||||
augroup lsp_document_highlight
|
||||
autocmd! * <buffer>
|
||||
autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
|
||||
autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
|
||||
augroup END
|
||||
]],
|
||||
false
|
||||
)
|
||||
vim.lsp.handlers["textDocument/documentHighlight"] = function(_, _, result, _)
|
||||
if not result then
|
||||
return
|
||||
end
|
||||
bufnr = api.nvim_get_current_buf()
|
||||
vim.lsp.util.buf_clear_references(bufnr)
|
||||
vim.lsp.util.buf_highlight_references(bufnr, result)
|
||||
end
|
||||
end
|
||||
|
||||
M.on_attach = function(client, bufnr)
|
||||
log("attaching")
|
||||
if lsp_status ~= nil then
|
||||
lsp_status.on_attach(client, bufnr)
|
||||
end
|
||||
require "lsp_signature".on_attach()
|
||||
diagnostic_map(bufnr)
|
||||
-- lspsaga
|
||||
require "utils.highlight".add_highlight()
|
||||
|
||||
api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
|
||||
|
||||
-- https://github.com/fsouza
|
||||
if client.resolved_capabilities.document_highlight then
|
||||
documentHighlight()
|
||||
end
|
||||
|
||||
require("navigator.lspclient.mapping").setup({client = client, bufnr = bufnr, cap = client.resolved_capabilities})
|
||||
|
||||
vim.cmd [[packadd vim-illuminate]]
|
||||
require "illuminate".on_attach(client)
|
||||
require "utils.lspkind".init()
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||
end
|
||||
|
||||
|
||||
|
||||
M.setup = function(cfg)
|
||||
return M
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,219 @@
|
||||
-- todo allow config passed in
|
||||
|
||||
local lspconfig = nil
|
||||
local lsp_status = nil
|
||||
if not packer_plugins["nvim-lua/lsp-status.nvim"] or not packer_plugins["lsp-status.nvim"].loaded then
|
||||
vim.cmd [[packadd lsp-status.nvim]]
|
||||
lsp_status = require("lsp-status")
|
||||
-- if lazyloading
|
||||
vim.cmd [[packadd nvim-lspconfig]]
|
||||
lspconfig = require "lspconfig"
|
||||
end
|
||||
|
||||
local cap = vim.lsp.protocol.make_client_capabilities()
|
||||
local on_attach = require("navigator.lspclient.attach").on_attach
|
||||
local lsp_status_cfg = {
|
||||
status_symbol = "",
|
||||
indicator_errors = "", --'',
|
||||
indicator_warnings = "", --'',
|
||||
indicator_info = "",
|
||||
--'',
|
||||
indicator_hint = "💡",
|
||||
indicator_ok = "",
|
||||
--'✔️',
|
||||
spinner_frames = {"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
|
||||
select_symbol = function(cursor_pos, symbol)
|
||||
if symbol.valuerange then
|
||||
local value_range = {
|
||||
["start"] = {
|
||||
character = 0,
|
||||
line = vim.fn.byte2line(symbol.valuerange[1])
|
||||
},
|
||||
["end"] = {
|
||||
character = 0,
|
||||
line = vim.fn.byte2line(symbol.valuerange[2])
|
||||
}
|
||||
}
|
||||
|
||||
return require("lsp-status.util").in_range(cursor_pos, value_range)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
-- local gopls = {}
|
||||
-- gopls["ui.completion.usePlaceholders"] = true
|
||||
|
||||
local golang_setup = {
|
||||
on_attach = on_attach,
|
||||
capabilities = cap,
|
||||
-- init_options = {
|
||||
-- useplaceholders = true,
|
||||
-- completeunimported = true
|
||||
-- },
|
||||
message_level = vim.lsp.protocol.MessageType.Error,
|
||||
cmd = {
|
||||
"gopls"
|
||||
|
||||
-- share the gopls instance if there is one already
|
||||
-- "-remote=auto",
|
||||
|
||||
--[[ debug options ]]
|
||||
--
|
||||
--"-logfile=auto",
|
||||
--"-debug=:0",
|
||||
--"-remote.debug=:0",
|
||||
--"-rpc.trace",
|
||||
},
|
||||
settings = {},
|
||||
root_dir = function(fname)
|
||||
local util = require("lspconfig").util
|
||||
return util.root_pattern("go.mod", ".git")(fname) or util.path.dirname(fname)
|
||||
end
|
||||
}
|
||||
local clang_cfg = {
|
||||
cmd = {
|
||||
"clangd",
|
||||
"--background-index",
|
||||
"--suggest-missing-includes",
|
||||
"--clang-tidy",
|
||||
"--header-insertion=iwyu"
|
||||
},
|
||||
on_attach = function(client)
|
||||
client.resolved_capabilities.document_formatting = true
|
||||
on_attach(client)
|
||||
end
|
||||
}
|
||||
|
||||
local sqls_cfg = {
|
||||
on_attach = function(client, bufnr)
|
||||
client.resolved_capabilities.execute_command = true
|
||||
lsp_status.on_attach(client, bufnr)
|
||||
require "utils.highlight".diagnositc_config_sign()
|
||||
require "sqls".setup {picker = "telescope"} -- or default
|
||||
end,
|
||||
settings = {
|
||||
cmd = {"sqls", "-config", "$HOME/.config/sqls/config.yml"},
|
||||
-- alterantively:
|
||||
-- connections = {
|
||||
-- {
|
||||
-- driver = 'postgresql',
|
||||
-- datasourcename = 'host=127.0.0.1 port=5432 user=postgres password=password dbname=user_db sslmode=disable',
|
||||
-- },
|
||||
-- },
|
||||
workspace = {
|
||||
library = {
|
||||
-- this loads the `lua` files from nvim into the runtime.
|
||||
[vim.fn.expand("$vimruntime/lua")] = true,
|
||||
[vim.fn.expand("~/repos/nvim/lua")] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-- lua setup
|
||||
local sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server"
|
||||
local sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server"
|
||||
|
||||
local lua_cfg = {
|
||||
cmd = {sumneko_binary, "-E", sumneko_root_path .. "/main.lua"},
|
||||
on_attach = on_attach,
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = {
|
||||
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
|
||||
version = "LuaJIT",
|
||||
-- Setup your lua path
|
||||
path = vim.split(package.path, ";")
|
||||
},
|
||||
diagnostics = {
|
||||
enable = true,
|
||||
-- Get the language server to recognize the `vim` global
|
||||
globals = {
|
||||
"vim",
|
||||
"describe",
|
||||
"it",
|
||||
"before_each",
|
||||
"after_each",
|
||||
"teardown",
|
||||
"pending"
|
||||
}
|
||||
},
|
||||
workspace = {
|
||||
-- Make the server aware of Neovim runtime files
|
||||
library = {
|
||||
[vim.fn.expand("$VIMRUNTIME/lua")] = true,
|
||||
[vim.fn.expand("$VIMRUNTIME/lua/vim")] = true,
|
||||
[vim.fn.expand("$VIMRUNTIME/lua/vim/lsp")] = true,
|
||||
-- [vim.fn.expand("~/repos/nvim/lua")] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local function lsp_status_setup()
|
||||
local servers = {
|
||||
"gopls",
|
||||
"tsserver",
|
||||
"flow",
|
||||
"bashls",
|
||||
"dockerls",
|
||||
"pyls",
|
||||
"sumneko_lua",
|
||||
"vimls",
|
||||
"html",
|
||||
"jsonls",
|
||||
"cssls",
|
||||
"yamlls",
|
||||
"clangd",
|
||||
"sqls"
|
||||
}
|
||||
|
||||
for _, lspclient in ipairs(servers) do
|
||||
if lsp_status ~= nl then
|
||||
lsp_status.register_progress()
|
||||
|
||||
lsp_status.config(lsp_status_cfg)
|
||||
end
|
||||
require "utils.highlight".diagnositc_config_sign()
|
||||
require "utils.highlight".add_highlight()
|
||||
end
|
||||
end
|
||||
|
||||
local function setup(user_opts)
|
||||
if lspconfig == nil then
|
||||
print("lsp-config need installed and enabled")
|
||||
return
|
||||
end
|
||||
|
||||
lsp_status_setup()
|
||||
|
||||
for _, lspclient in ipairs({"tsserver", "bashls", "flow", "dockerls", "vimls", "html", "jsonls", "cssls", "yamlls"}) do
|
||||
lspconfig[lspclient].setup {
|
||||
message_level = vim.lsp.protocol.MessageType.error,
|
||||
log_level = vim.lsp.protocol.MessageType.error,
|
||||
on_attach = on_attach,
|
||||
capabilities = lsp_status.capabilities
|
||||
}
|
||||
end
|
||||
|
||||
lspconfig.gopls.setup(golang_setup)
|
||||
lspconfig.sqls.setup(sqls_cfg)
|
||||
|
||||
require "lspconfig".sumneko_lua.setup(lua_cfg)
|
||||
|
||||
lspconfig.clangd.setup(clang_cfg)
|
||||
servers = {
|
||||
"dockerls",
|
||||
"bashls",
|
||||
"rust_analyzer",
|
||||
"pyls"
|
||||
}
|
||||
|
||||
for _, server in ipairs(servers) do
|
||||
lspconfig[server].setup {
|
||||
on_attach = on_attach
|
||||
}
|
||||
end
|
||||
end
|
||||
return {setup = setup, cap = cap}
|
@ -0,0 +1,29 @@
|
||||
local lsp = require("vim.lsp")
|
||||
|
||||
vim.cmd [[packadd lspsaga.nvim]]
|
||||
local saga = require "lspsaga"
|
||||
saga.init_lsp_saga()
|
||||
M={}
|
||||
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||
|
||||
function M.reload_lsp()
|
||||
vim.lsp.stop_client(vim.lsp.get_active_clients())
|
||||
vim.cmd [[edit]]
|
||||
end
|
||||
|
||||
function M.open_lsp_log()
|
||||
local path = vim.lsp.get_log_path()
|
||||
vim.cmd("edit " .. path)
|
||||
end
|
||||
|
||||
vim.cmd("command! -nargs=0 LspLog call v:lua.open_lsp_log()")
|
||||
vim.cmd("command! -nargs=0 LspRestart call v:lua.reload_lsp()")
|
||||
|
||||
print("loading lsp client")
|
||||
local cfg = {}
|
||||
require('lsp.clients').setup(cfg)
|
||||
require('lsp.mappings').setup(cfg)
|
||||
return M
|
@ -0,0 +1,48 @@
|
||||
local M = {}
|
||||
local api = vim.api
|
||||
|
||||
-- lsp sign ﮻ ﯭ ﳀ
|
||||
function M.diagnositc_config_sign()
|
||||
vim.fn.sign_define('LspDiagnosticsSignError', {text='', texthl='LspDiagnosticsSignError',linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignWarning', {text='', texthl='LspDiagnosticsSignWarning', linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignInformation', {text='', texthl='LspDiagnosticsSignInformation', linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignHint', {text='💡', texthl='LspDiagnosticsSignHint', linehl='', numhl=''})
|
||||
end
|
||||
|
||||
function M.add_highlight()
|
||||
|
||||
-- lsp system default
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineError SpellBad")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineWarning SpellRare")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineInformation SpellRare")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineHint SpellRare")
|
||||
|
||||
|
||||
-- lspsaga
|
||||
api.nvim_command("hi LspFloatWinBorder guifg=black")
|
||||
api.nvim_command("hi def link TargetWord Error")
|
||||
api.nvim_command("hi def link ReferencesCount Title")
|
||||
api.nvim_command("hi def link DefinitionCount Title")
|
||||
api.nvim_command("hi def link TargetFileName Comment")
|
||||
api.nvim_command("hi def link DefinitionIcon Special")
|
||||
api.nvim_command("hi def link ReferencesIcon Special")
|
||||
api.nvim_command("hi def link HelpTitle Comment")
|
||||
api.nvim_command("hi def link HelpItem Comment")
|
||||
|
||||
|
||||
-- diagnostic for lspsaga, overwrite if needed
|
||||
-- api.nvim_command("hi DiagnosticTruncateLine guifg=#6699cc gui=bold")
|
||||
-- api.nvim_command("hi def link DiagnosticError Error")
|
||||
-- api.nvim_command("hi def link DiagnosticWarning WarningMsg")
|
||||
-- api.nvim_command("hi DiagnosticInformation guifg=#6699cc gui=bold")
|
||||
-- api.nvim_command("hi DiagnosticHint guifg=#56b6c2 gui=bold")
|
||||
|
||||
-- for nvim version 0.5 2020-11
|
||||
-- api.nvim_command("sign define LspDiagnosticsErrorSign text= texthl=LspDiagnosticsError linehl= numhl=")
|
||||
-- api.nvim_command("sign define LspDiagnosticsWarningSign text= texthl=LspDiagnosticsWarning linehl= numhl=")
|
||||
|
||||
api.nvim_command("hi def link DefinitionPreviewTitle Title")
|
||||
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,7 @@
|
||||
local M = {}
|
||||
M.setup = function(cfg)
|
||||
cfg = cfg or {}
|
||||
require('navigator.lspclient.clients').setup(cfg)
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,38 @@
|
||||
local kind_symbols = {
|
||||
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 = '',
|
||||
Default = '',
|
||||
}
|
||||
local CompletionItemKind = {'', 'ƒ', '', '', 'ﴲ', '', '', 'ﰮ', '', '', '', '', '了', '', '', '', '', '', '', '', '', '', 'ﳅ', '', '', ''}
|
||||
|
||||
function lspkind.kind(kind)
|
||||
-- require('vim.lsp.protocol').CompletionItemKind = {'', 'ƒ', '', '', 'ﴲ', '', '', 'ﰮ', '', '', '', '', '了', '', '', '', '', '', '', '', '', '', 'ﳅ', '', '', ''}
|
||||
return CompletionItemKind[kind]
|
||||
end
|
||||
|
||||
|
||||
|
||||
return lspkind
|
@ -0,0 +1,142 @@
|
||||
local log = require "navigator.util".log
|
||||
local function set_keymap(...)
|
||||
vim.api.nvim_set_keymap(...)
|
||||
end
|
||||
|
||||
local event_hdlrs = {
|
||||
{ev = "BufWritePre", func = "diagnostic.set_loclist({open_loclist = false})"},
|
||||
{ev = "CursorHold", func = "document_highlight()"},
|
||||
{ev = "CursorHoldI", func = "document_highlight()"},
|
||||
{ev = "CursorMoved", func = "clear_references()"}
|
||||
}
|
||||
|
||||
local key_maps = {
|
||||
{key = "gr", func = "references()"},
|
||||
{mode = "i", key = "<M-k>", func = "signature_help()"},
|
||||
{key = "gs", func = "signature_help()"},
|
||||
{key = "g0", func = "document_symbol()"},
|
||||
{key = "gW", func = "workspace_symbol()"},
|
||||
{key = "<c-]>", func = "definition()"},
|
||||
{key = "gD", func = "declaration()"},
|
||||
{key = "gp", func = "require('navigator.definition').definition_preview()"},
|
||||
|
||||
{key = "K", func = "hover()"},
|
||||
{key = "ga", mode = 'n', func = "code_action()"},
|
||||
{key = "ca", mode = 'v', func = "range_code_action()"},
|
||||
|
||||
{key = "<Leader>re", func = "rename()"},
|
||||
{key = "<Leader>gi", func = "incoming_calls()"},
|
||||
{key = "<Leader>go", func = "outgoing_calls()"},
|
||||
{key = "gi", func = "implementation()"},
|
||||
{key = "gt", func = "type_definition()"},
|
||||
{key = "gL", func = "diagnostic.show_line_diagnostics()"},
|
||||
{key = "gG", func = "require('navigator.diagnostics').show_diagnostic()"},
|
||||
{key = "]d", func = "diagnostic.goto_next()"},
|
||||
{key = "[d", func = "diagnostic.goto_prev()"},
|
||||
|
||||
{key = "<C-LeftMouse>", func = "definition()"},
|
||||
{key = "g<LeftMouse>", func = "implementation()"}
|
||||
}
|
||||
|
||||
local function set_mapping(user_opts)
|
||||
local opts = {noremap = true, silent = true}
|
||||
user_opts = user_opts or {}
|
||||
|
||||
local user_key = user_opts.keymaps or {}
|
||||
local bufnr = user_opts.bufnr or 0
|
||||
local opts = { noremap=true, silent=true }
|
||||
|
||||
local function buf_set_keymap(...)
|
||||
vim.api.nvim_buf_set_keymap(bufnr, ...)
|
||||
end
|
||||
|
||||
-- local function buf_set_option(...)
|
||||
-- vim.api.nvim_buf_set_option(bufnr, ...)
|
||||
-- end
|
||||
for _, v in pairs(user_key) do
|
||||
local exists = false
|
||||
for _, default in pairs(key_maps) do
|
||||
if v.func == default.func then
|
||||
default.key, exists = v.key, true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not exists then
|
||||
table.insert(key_maps, v)
|
||||
end
|
||||
end
|
||||
|
||||
-- local key_opts = {vim.tbl_deep_extend("force", key_maps, unpack(result))}
|
||||
for _, value in pairs(key_maps) do
|
||||
local f = "<Cmd>lua vim.lsp.buf." .. value.func .. "<CR>"
|
||||
if string.find(value.func, 'require') then
|
||||
f = "<Cmd>lua " .. value.func .. "<CR>"
|
||||
else if string.find(value.func, 'diagnostic') then
|
||||
f = "<Cmd>lua vim.lsp." .. value.func .. "<CR>"
|
||||
end
|
||||
local k = value.key
|
||||
local m = value.mode or "n"
|
||||
buf_set_keymap(m, k, f, opts)
|
||||
end
|
||||
|
||||
-- format setup
|
||||
|
||||
if user_opts.cap.document_formatting then
|
||||
buf_set_keymap("n", "<space>f", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
|
||||
vim.cmd([[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting()]])
|
||||
end
|
||||
if user_opts.cap.document_range_formatting then
|
||||
buf_set_keymap("v", "<space>f", "<cmd>lua vim.lsp.buf.range_formatting()<CR>", opts)
|
||||
end
|
||||
end
|
||||
|
||||
local function set_event_handler(user_opts)
|
||||
user_opts = user_opts or {}
|
||||
local file_types = "c,cpp,h,go,python,vim,sh,javascript,html,css,lua,typescript,rust"
|
||||
-- local format_files = "c,cpp,h,go,python,vim,javascript,typescript" --html,css,
|
||||
vim.api.nvim_command [[augroup nvim_lsp_autos]]
|
||||
vim.api.nvim_command [[autocmd!]]
|
||||
|
||||
for _, value in pairs(event_hdlrs) do
|
||||
local f = ""
|
||||
if string.find(value.func, "diagnostic") then
|
||||
f = "lua vim.lsp." .. value.func
|
||||
else
|
||||
f = "lua vim.lsp.buf." .. value.func
|
||||
end
|
||||
local cmd = "autocmd FileType " .. file_types .. " autocmd nvim_lsp_autos " .. value.ev .. " <buffer> silent! " .. f
|
||||
vim.api.nvim_command(cmd)
|
||||
end
|
||||
vim.api.nvim_command([[augroup END]])
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.setup(user_opts)
|
||||
set_mapping(user_opts)
|
||||
set_event_handler(user_opts)
|
||||
local cap = user_opts.cap or {}
|
||||
if cap.call_hierarchy then
|
||||
vim.lsp.handlers["callHierarchy/incomingCalls"] = require "navigator.hierarchy".incoming_calls_handler
|
||||
vim.lsp.handlers["callHierarchy/outgoingCalls"] = require "navigator.hierarchy".outgoing_calls_handler
|
||||
end
|
||||
|
||||
vim.lsp.handlers["textDocument/references"] = require "navigator.reference".reference_handler
|
||||
vim.lsp.handlers["textDocument/codeAction"] = require "navigator.codeAction".code_action_handler
|
||||
vim.lsp.handlers["textDocument/definition"] = require "navigator.definition".definition_handler
|
||||
|
||||
if cap.declaration then
|
||||
vim.lsp.handlers["textDocument/declaration"] = require "navigator.definition".declaration_handler
|
||||
end
|
||||
|
||||
vim.lsp.handlers["textDocument/typeDefinition"] = require "navigator.definition".typeDefinition_handler
|
||||
vim.lsp.handlers["textDocument/implementation"] = require "navigator.implementation".implementation_handler
|
||||
|
||||
vim.lsp.handlers["textDocument/documentSymbol"] = require "navigator.symbols".symbol_handler
|
||||
vim.lsp.handlers["workspace/symbol"] = require "navigator.symbols".symbol_handler
|
||||
vim.lsp.handlers["textDocument/publishDiagnostics"] = require'navigator.diagnostics'.diagnostic_handler
|
||||
|
||||
-- vim.lsp.handlers["textDocument/hover"] = require 'navigator.hover'.hover_handler
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,128 @@
|
||||
local M = {}
|
||||
local util = require "navigator.util"
|
||||
local lsp = require "vim.lsp"
|
||||
local log = require "navigator.util".log
|
||||
function M.lines_from_locations(locations, include_filename)
|
||||
local fnamemodify = (function(filename)
|
||||
if include_filename then
|
||||
return vim.fn.fnamemodify(filename, ":~:.") .. ":"
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end)
|
||||
|
||||
local lines = {}
|
||||
for _, loc in ipairs(locations) do
|
||||
table.insert(
|
||||
lines,
|
||||
(fnamemodify(loc["filename"]) .. loc["lnum"] .. ":" .. loc["col"] .. ": " .. vim.trim(loc["text"]))
|
||||
)
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
local function extract_result(results_lsp)
|
||||
if results_lsp then
|
||||
local results = {}
|
||||
for _, server_results in pairs(results_lsp) do
|
||||
if server_results.result then
|
||||
vim.list_extend(results, server_results.result)
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
end
|
||||
|
||||
function M.check_capabilities(feature, client_id)
|
||||
local clients = lsp.buf_get_clients(client_id or 0)
|
||||
|
||||
local supported_client = false
|
||||
for _, client in pairs(clients) do
|
||||
supported_client = client.resolved_capabilities[feature]
|
||||
if supported_client then
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
if supported_client then
|
||||
return true
|
||||
else
|
||||
if #clients == 0 then
|
||||
print("LSP: no client attached")
|
||||
else
|
||||
print("LSP: server does not support " .. feature)
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function M.call_sync(method, params, opts, handler)
|
||||
params = params or {}
|
||||
opts = opts or {}
|
||||
local results_lsp, err = lsp.buf_request_sync(0, method, params, opts.timeout or vim.g.navtator_timeout)
|
||||
|
||||
handler(err, method, extract_result(results_lsp), nil, nil)
|
||||
end
|
||||
|
||||
function M.call_async(method, params, handler)
|
||||
params = params or {}
|
||||
local callback = function(...)
|
||||
util.show(...)
|
||||
handler(...)
|
||||
end
|
||||
local results_lsp, canceller = lsp.buf_request(0, method, params, callback)
|
||||
return results_lsp, canceller
|
||||
-- handler(err, method, extract_result(results_lsp), nil, nil)
|
||||
end
|
||||
|
||||
function M.locations_to_items(locations)
|
||||
local cwd = vim.fn.getcwd(0)
|
||||
if not locations or vim.tbl_isempty(locations) then
|
||||
print("list not avalible")
|
||||
return
|
||||
end
|
||||
|
||||
local items = {} -- lsp.util.locations_to_items(locations)
|
||||
-- items and locations may not matching
|
||||
table.sort(
|
||||
locations,
|
||||
function(i, j)
|
||||
if i.uri == j.uri then
|
||||
if i.range and i.range.start then
|
||||
return i.range.start.line < j.range.start.line
|
||||
end
|
||||
return false
|
||||
else
|
||||
return i.uri < j.uri
|
||||
end
|
||||
end
|
||||
)
|
||||
for i, loc in ipairs(locations) do
|
||||
local item = lsp.util.locations_to_items({loc})[1]
|
||||
item.uri = locations[i].uri
|
||||
item.range = locations[i].range
|
||||
item.filename = assert(vim.uri_to_fname(item.uri))
|
||||
local filename = item.filename:gsub(cwd .. "/", "./", 1)
|
||||
item.display_filename = filename or item.filename
|
||||
item.rpath = util.get_relative_path(cwd, item.filename)
|
||||
table.insert(items, item)
|
||||
end
|
||||
|
||||
-- insert data into lines and loc
|
||||
-- for i, loc in ipairs(items) do
|
||||
-- log(items[i], locations[i])
|
||||
-- local filename = loc.filename:gsub(cwd .. "/", "./", 1)
|
||||
-- items[i].uri = locations[i].uri
|
||||
-- items[i].range = locations[i].range
|
||||
-- items[i].filename = assert(vim.uri_to_fname(loc.uri))
|
||||
-- items[i].display_filename = filename or items[i].filename
|
||||
-- items[i].rpath = util.get_relative_path(cwd, loc.filename)
|
||||
-- log(items[i], locations[i])
|
||||
-- end
|
||||
return items
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,453 @@
|
||||
--[[ -- incomming/outgoing
|
||||
dir from result { {
|
||||
from = {
|
||||
detail = "command-line-arguments • interface.go",
|
||||
kind = 12,
|
||||
name = "m2",
|
||||
range = {
|
||||
end = {
|
||||
character = 7,
|
||||
line = 39
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 39
|
||||
}
|
||||
},
|
||||
selectionRange = {
|
||||
end = {
|
||||
character = 7,
|
||||
line = 39
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 39
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
fromRanges = { {
|
||||
end = {
|
||||
character = 8,
|
||||
line = 40
|
||||
},
|
||||
start = {
|
||||
character = 1,
|
||||
line = 40
|
||||
}
|
||||
} }
|
||||
}, {
|
||||
from = {
|
||||
detail = "command-line-arguments • interface.go",
|
||||
kind = 12,
|
||||
name = "main",
|
||||
range = {
|
||||
end = {
|
||||
character = 9,
|
||||
line = 43
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 43
|
||||
}
|
||||
},
|
||||
selectionRange = {
|
||||
end = {
|
||||
character = 9,
|
||||
line = 43
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 43
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
fromRanges = { {
|
||||
end = {
|
||||
character = 11,
|
||||
line = 47
|
||||
},
|
||||
start = {
|
||||
character = 4,
|
||||
line = 47
|
||||
}
|
||||
}, {
|
||||
end = {
|
||||
character = 11,
|
||||
line = 48
|
||||
},
|
||||
start = {
|
||||
character = 4,
|
||||
line = 48
|
||||
}
|
||||
} }
|
||||
} }
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- [[ locations/reference from lsp
|
||||
{ {
|
||||
range = {
|
||||
["end"] = {
|
||||
character = 20,
|
||||
line = 26
|
||||
},
|
||||
start = {
|
||||
character = 16,
|
||||
line = 26
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
}, {
|
||||
range = {
|
||||
["end"] = {
|
||||
character = 22,
|
||||
line = 35
|
||||
},
|
||||
start = {
|
||||
character = 18,
|
||||
line = 35
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
} }
|
||||
--]]
|
||||
|
||||
|
||||
-- definition
|
||||
|
||||
definition.lua:9: { {
|
||||
range = {
|
||||
end = {
|
||||
character = 12,
|
||||
line = 33
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 33
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
} }
|
||||
|
||||
|
||||
-- def preview
|
||||
|
||||
def-preview {
|
||||
[3] = {
|
||||
result = { {
|
||||
range = {
|
||||
end = {
|
||||
character = 12,
|
||||
line = 33
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 33
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-- symbol
|
||||
{ {
|
||||
containerName = "command-line-arguments",
|
||||
kind = 11,
|
||||
location = {
|
||||
range = {
|
||||
end = {
|
||||
character = 13,
|
||||
line = 7
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 7
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
name = "command-line-arguments.geometry"
|
||||
}, {
|
||||
containerName = "command-line-arguments",
|
||||
kind = 23,
|
||||
location = {
|
||||
range = {
|
||||
end = {
|
||||
character = 9,
|
||||
line = 12
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 12
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
name = "command-line-arguments.rect"
|
||||
}, {
|
||||
containerName = "command-line-arguments",
|
||||
kind = 12,
|
||||
location = {
|
||||
range = {
|
||||
end = {
|
||||
character = 9,
|
||||
line = 43
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 43
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
name = "command-line-arguments.main"
|
||||
}, {
|
||||
containerName = "command-line-arguments",
|
||||
kind = 6,
|
||||
location = {
|
||||
range = {
|
||||
end = {
|
||||
character = 8,
|
||||
line = 8
|
||||
},
|
||||
start = {
|
||||
character = 4,
|
||||
line = 8
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
name = "command-line-arguments.geometry.area"
|
||||
}, {
|
||||
containerName = "command-line-arguments",
|
||||
kind = 8,
|
||||
location = {
|
||||
range = {
|
||||
end = {
|
||||
character = 9,
|
||||
line = 13
|
||||
},
|
||||
start = {
|
||||
character = 4,
|
||||
line = 13
|
||||
}
|
||||
},
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
},
|
||||
name = "command-line-arguments.rect.width"
|
||||
}}
|
||||
|
||||
|
||||
{
|
||||
diagnostics = { {
|
||||
code = "UnusedVar",
|
||||
codeDescription = {
|
||||
href = "https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#UnusedVar"
|
||||
},
|
||||
message = "d declared but not used",
|
||||
range = {
|
||||
end = {
|
||||
character = 5,
|
||||
line = 46
|
||||
},
|
||||
start = {
|
||||
character = 4,
|
||||
line = 46
|
||||
}
|
||||
},
|
||||
severity = 1,
|
||||
source = "compiler"
|
||||
}, {
|
||||
code = "WrongArgCount",
|
||||
codeDescription = {
|
||||
href = "https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#WrongArgCount"
|
||||
},
|
||||
message = "missing argument in conversion to circle",
|
||||
range = {
|
||||
end = {
|
||||
character = 17,
|
||||
line = 46
|
||||
},
|
||||
start = {
|
||||
character = 9,
|
||||
line = 46
|
||||
}
|
||||
},
|
||||
severity = 1,
|
||||
source = "compiler"
|
||||
} },
|
||||
uri = "file:///Users/ray.xu/lsp-test/go/interface.go"
|
||||
}
|
||||
|
||||
|
||||
-- range actions
|
||||
{ {
|
||||
edit = {
|
||||
documentChanges = { {
|
||||
edits = { {
|
||||
newText = '\nimport (\n\t"fmt"\n\t"log"\n)\n',
|
||||
range = {
|
||||
end = {
|
||||
character = 0,
|
||||
line = 1
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 1
|
||||
}
|
||||
}
|
||||
} },
|
||||
textDocument = {
|
||||
uri = "file:///Users/ray.xu/lsp_test/go/ref.go",
|
||||
version = 0
|
||||
}
|
||||
} }
|
||||
},
|
||||
kind = "source.organizeImports",
|
||||
title = "Organize Imports"
|
||||
}, {
|
||||
command = {
|
||||
arguments = { {
|
||||
Fix = "undeclared_name",
|
||||
Range = {
|
||||
end = {
|
||||
character = 20,
|
||||
line = 4
|
||||
},
|
||||
start = {
|
||||
character = 16,
|
||||
line = 4
|
||||
}
|
||||
},
|
||||
URI = "file:///Users/ray.xu/lsp_test/go/ref.go"
|
||||
} },
|
||||
command = "gopls.apply_fix",
|
||||
title = "undeclared name: rect"
|
||||
},
|
||||
diagnostics = { {
|
||||
code = "UndeclaredName",
|
||||
codeDescription = {
|
||||
href = "https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#UndeclaredName"
|
||||
},
|
||||
message = "undeclared name: rect",
|
||||
range = {
|
||||
end = {
|
||||
character = 20,
|
||||
line = 4
|
||||
},
|
||||
start = {
|
||||
character = 16,
|
||||
line = 4
|
||||
}
|
||||
},
|
||||
severity = 1,
|
||||
source = "compiler",
|
||||
tags = { 1 }
|
||||
} },
|
||||
edit = {},
|
||||
kind = "quickfix",
|
||||
title = "undeclared name: rect"
|
||||
}, {
|
||||
command = {
|
||||
arguments = { {
|
||||
Fix = "extract_function",
|
||||
Range = {
|
||||
end = {
|
||||
character = 16,
|
||||
line = 6
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 4
|
||||
}
|
||||
},
|
||||
URI = "file:///Users/ray.xu/lsp_test/go/ref.go"
|
||||
} },
|
||||
command = "gopls.apply_fix",
|
||||
title = "Extract to function"
|
||||
},
|
||||
edit = {},
|
||||
kind = "refactor.extract",
|
||||
title = "Extract to function"
|
||||
} }
|
||||
|
||||
|
||||
|
||||
-- code action
|
||||
|
||||
{ {
|
||||
diagnostics = { {
|
||||
code = "UndeclaredName",
|
||||
codeDescription = {
|
||||
href = "https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#UndeclaredName"
|
||||
},
|
||||
message = "undeclared name: log",
|
||||
range = {
|
||||
end = {
|
||||
character = 4,
|
||||
line = 6
|
||||
},
|
||||
start = {
|
||||
character = 1,
|
||||
line = 6
|
||||
}
|
||||
},
|
||||
severity = 1,
|
||||
source = "compiler"
|
||||
} },
|
||||
edit = {
|
||||
documentChanges = { {
|
||||
edits = { {
|
||||
newText = '\nimport "log"\n',
|
||||
range = {
|
||||
end = {
|
||||
character = 0,
|
||||
line = 1
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 1
|
||||
}
|
||||
}
|
||||
} },
|
||||
textDocument = {
|
||||
uri = "file:///Users/ray.xu/lsp_test/go/ref.go",
|
||||
version = 0
|
||||
}
|
||||
} }
|
||||
},
|
||||
kind = "quickfix",
|
||||
title = 'Add import: "log"'
|
||||
}, {
|
||||
edit = {
|
||||
documentChanges = { {
|
||||
edits = { {
|
||||
newText = '\nimport (\n\t"fmt"\n\t"log"\n)\n',
|
||||
range = {
|
||||
end = {
|
||||
character = 0,
|
||||
line = 1
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 1
|
||||
}
|
||||
}
|
||||
} },
|
||||
textDocument = {
|
||||
uri = "file:///Users/ray.xu/lsp_test/go/ref.go",
|
||||
version = 0
|
||||
}
|
||||
} }
|
||||
},
|
||||
kind = "source.organizeImports",
|
||||
title = "Organize Imports"
|
||||
} }
|
@ -0,0 +1,32 @@
|
||||
local util = require "navigator.util"
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local gui = require "navigator.gui"
|
||||
local log = require "navigator.util".log
|
||||
-- local log = util.log
|
||||
-- local partial = util.partial
|
||||
-- local cwd = vim.fn.getcwd(0)
|
||||
-- local lsphelper = require "navigator.lspwrapper"
|
||||
local locations_to_items = lsphelper.locations_to_items
|
||||
|
||||
--vim.api.nvim_set_option("navtator_options", {width = 90, height = 60, location = require "navigator.location".center})
|
||||
-- local options = vim.g.navtator_options or {width = 60, height = 40, location = location.center}
|
||||
|
||||
|
||||
local function ref_hdlr(arg1, api, locations, num, bufnr)
|
||||
local opts = {}
|
||||
|
||||
-- log("arg1", arg1)
|
||||
-- log(api)
|
||||
-- log("num", num)
|
||||
-- log("bfnr", bufnr)
|
||||
|
||||
if locations == nil or vim.tbl_isempty(locations) then
|
||||
print "References not found"
|
||||
return
|
||||
end
|
||||
log(locations)
|
||||
local items = locations_to_items(locations)
|
||||
gui.new_list_view({items = items, api = 'Reference'})
|
||||
end
|
||||
|
||||
return { reference_handler = ref_hdlr }
|
@ -0,0 +1,115 @@
|
||||
local gui = require "navigator.gui"
|
||||
local M = {}
|
||||
local log = require "navigator.util".log
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local locations_to_items = lsphelper.locations_to_items
|
||||
|
||||
function M.document_symbols(opts)
|
||||
opts = opts or {}
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
params.context = {includeDeclaration = true}
|
||||
params.query = ""
|
||||
local results_lsp = vim.lsp.buf_request_sync(0, "textDocument/documentSymbol", params, opts.timeout or 10000)
|
||||
local locations = {}
|
||||
log(results_lsp)
|
||||
for _, server_results in pairs(results_lsp) do
|
||||
if server_results.result then
|
||||
vim.list_extend(locations, vim.lsp.util.symbols_to_items(server_results.result) or {})
|
||||
end
|
||||
end
|
||||
local lines = {}
|
||||
|
||||
for _, loc in ipairs(locations) do
|
||||
table.insert(lines, string.format("%s:%s:%s", loc.filename, loc.lnum, loc.text))
|
||||
end
|
||||
local cmd = table.concat(lines, "\n")
|
||||
if #lines > 0 then
|
||||
gui.new_list_view({data = lines})
|
||||
else
|
||||
print("symbols not found")
|
||||
end
|
||||
end
|
||||
|
||||
function M.workspace_symbols(opts)
|
||||
opts = opts or {}
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
params.context = {includeDeclaration = true}
|
||||
params.query = ""
|
||||
local results_lsp = vim.lsp.buf_request_sync(0, "workspace/symbol", params, opts.timeout or 10000)
|
||||
|
||||
log(results_lsp)
|
||||
local locations = {}
|
||||
for _, server_results in pairs(results_lsp) do
|
||||
if server_results.result then
|
||||
vim.list_extend(locations, vim.lsp.util.symbols_to_items(server_results.result) or {})
|
||||
end
|
||||
end
|
||||
local lines = {}
|
||||
|
||||
for _, loc in ipairs(locations) do
|
||||
table.insert(lines, string.format("%s:%s:%s", loc.filename, loc.lnum, loc.text))
|
||||
end
|
||||
if #lines > 0 then
|
||||
gui.new_list_view({data = lines})
|
||||
else
|
||||
print("symbols not found")
|
||||
end
|
||||
end
|
||||
|
||||
function M.symbol_handler(_, _, result, _, bufnr)
|
||||
if not result or vim.tbl_isempty(result) then
|
||||
print("symbol not found")
|
||||
return
|
||||
end
|
||||
-- log(result)
|
||||
local locations = {}
|
||||
for i = 1, #result do
|
||||
local item = result[i].location
|
||||
item.kind = result[i].kind
|
||||
item.containerName = result[i].containerName
|
||||
item.name = result[i].name
|
||||
item.text = result[i].name
|
||||
if #item.containerName > 0 then
|
||||
item.text = item.text:gsub(item.containerName, '', 1)
|
||||
end
|
||||
table.insert(locations, item)
|
||||
end
|
||||
local items = locations_to_items(locations)
|
||||
gui.new_list_view({items = items, prompt = true})
|
||||
|
||||
-- if locations == nil or vim.tbl_isempty(locations) then
|
||||
-- print "References not found"
|
||||
-- return
|
||||
-- end
|
||||
-- local items = locations_to_items(locations)
|
||||
-- gui.new_list_view({items = items})
|
||||
-- local filename = vim.api.nvim_buf_get_name(bufnr)
|
||||
-- local items = vim.lsp.util.symbols_to_items(result, bufnr)
|
||||
-- local data = {}
|
||||
-- for i, item in pairs(action.items) do
|
||||
-- data[i] = item.text
|
||||
-- if filename ~= item.filename then
|
||||
-- local cwd = vim.fn.getcwd(0) .. "/"
|
||||
-- local add = util.get_relative_path(cwd, item.filename)
|
||||
-- data[i] = data[i] .. " - " .. add
|
||||
-- end
|
||||
-- item.text = nil
|
||||
-- end
|
||||
-- opts.data = data
|
||||
-- action.popup = popfix:new(opts)
|
||||
-- if not action.popup then
|
||||
-- action.items = nil
|
||||
-- end
|
||||
-- if action.popup.list then
|
||||
-- util.setFiletype(action.popup.list.buffer, "lsputil_symbols_list")
|
||||
-- end
|
||||
-- if action.popup.preview then
|
||||
-- util.setFiletype(action.popup.preview.buffer, "lsputil_symbols_preview")
|
||||
-- end
|
||||
-- if action.popup.prompt then
|
||||
-- util.setFiletype(action.popup.prompt.buffer, "lsputil_symbols_prompt")
|
||||
-- end
|
||||
-- opts.data = nil
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,231 @@
|
||||
-- retreives data form file
|
||||
-- and line to highlight
|
||||
-- Some of function copied from https://github.com/RishabhRD/nvim-lsputils
|
||||
|
||||
local M = {
|
||||
log_path = vim.lsp.get_log_path()
|
||||
}
|
||||
function M.get_data_from_file(filename, startLine)
|
||||
local displayLine
|
||||
if startLine < 3 then
|
||||
displayLine = startLine
|
||||
startLine = 0
|
||||
else
|
||||
startLine = startLine - 2
|
||||
displayLine = 2
|
||||
end
|
||||
local uri = "file:///" .. filename
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
vim.fn.bufload(bufnr)
|
||||
local data = vim.api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
|
||||
if data == nil or vim.tbl_isempty(data) then
|
||||
startLine = nil
|
||||
else
|
||||
local len = #data
|
||||
startLine = startLine + 1
|
||||
for i = 1, len, 1 do
|
||||
data[i] = startLine .. " " .. data[i]
|
||||
startLine = startLine + 1
|
||||
end
|
||||
end
|
||||
return {
|
||||
data = data,
|
||||
line = displayLine
|
||||
}
|
||||
end
|
||||
|
||||
function M.get_base(path)
|
||||
local len = #path
|
||||
for i = len, 1, -1 do
|
||||
if path:sub(i, i) == "/" then
|
||||
local ret = path:sub(i + 1, len)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getDir(path)
|
||||
local data = {}
|
||||
local len = #path
|
||||
if len <= 1 then return nil end
|
||||
local last_index = 1
|
||||
for i = 2, len do
|
||||
local cur_char = path:sub(i,i)
|
||||
if cur_char == '/' then
|
||||
local my_data = path:sub(last_index + 1, i - 1)
|
||||
table.insert(data, my_data)
|
||||
last_index = i
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
function M.get_relative_path(base_path, my_path)
|
||||
local base_data = getDir(base_path)
|
||||
local my_data = getDir(my_path)
|
||||
local base_len = #base_data
|
||||
local my_len = #my_data
|
||||
|
||||
if base_len > my_len then
|
||||
return my_path
|
||||
end
|
||||
|
||||
if base_data[1] ~= my_data[1] then
|
||||
return my_path
|
||||
end
|
||||
|
||||
local cur = 0
|
||||
for i = 1, base_len do
|
||||
if base_data[i] ~= my_data[i] then
|
||||
break
|
||||
end
|
||||
cur = i
|
||||
end
|
||||
local data = ""
|
||||
for i = cur + 1, my_len do
|
||||
data = data .. my_data[i] .. "/"
|
||||
end
|
||||
data = data .. M.get_base(my_path)
|
||||
return data
|
||||
end
|
||||
|
||||
local default_config = {
|
||||
plugin = "navigator",
|
||||
use_console = false,
|
||||
use_file = true,
|
||||
level = "info"
|
||||
}
|
||||
|
||||
M._log = require('guihua.log').new({level='debug'}, true)
|
||||
|
||||
-- add log to you lsp.log
|
||||
M.log = M._log.info
|
||||
M.verbose = M._log.debug
|
||||
|
||||
function M.fmt(...)
|
||||
M._log.fmt_info(...)
|
||||
end
|
||||
|
||||
function M.split(inputstr, sep)
|
||||
if sep == nil then
|
||||
sep = "%s"
|
||||
end
|
||||
local t = {}
|
||||
for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
|
||||
table.insert(t, str)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
function M.trim_space(s)
|
||||
return s:match("^%s*(.-)%s*$")
|
||||
end
|
||||
|
||||
function M.quickfix_extract(line)
|
||||
-- check if it is a line of file pos been selected
|
||||
local split = M.split
|
||||
line = M.trim_space(line)
|
||||
local sep = split(line, " ")
|
||||
if #sep < 2 then
|
||||
M.log(line)
|
||||
return nil
|
||||
end
|
||||
sep = split(sep[1], ":")
|
||||
if #sep < 3 then
|
||||
M.log(line)
|
||||
return nil
|
||||
end
|
||||
local location = {uri = "file:///" .. sep[1], range = {start = {line = sep[2] - 3 > 0 and sep[2] - 3 or 1}}}
|
||||
location.range["end"] = {line = sep[2] + 15}
|
||||
return location
|
||||
end
|
||||
|
||||
function M.getArgs(inputstr)
|
||||
local sep = "%s"
|
||||
local t = {}
|
||||
local cmd
|
||||
for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
|
||||
if not cmd then
|
||||
cmd = str
|
||||
else
|
||||
table.insert(t, str)
|
||||
end
|
||||
end
|
||||
return cmd, t
|
||||
end
|
||||
|
||||
function M.p(t)
|
||||
print(vim.inspect(t))
|
||||
end
|
||||
|
||||
function M.printError(msg)
|
||||
vim.cmd("echohl ErrorMsg")
|
||||
vim.cmd(string.format([[echomsg '%s']], msg))
|
||||
vim.cmd("echohl None")
|
||||
end
|
||||
|
||||
function M.reload()
|
||||
vim.lsp.stop_client(vim.lsp.get_active_clients())
|
||||
vim.cmd [[edit]]
|
||||
end
|
||||
|
||||
function M.open_log()
|
||||
local path = vim.lsp.get_log_path()
|
||||
vim.cmd("edit " .. path)
|
||||
end
|
||||
|
||||
function table.pack(...)
|
||||
return {n = select("#", ...), ...}
|
||||
end
|
||||
|
||||
function M.show(...)
|
||||
local string = ""
|
||||
|
||||
local args = table.pack(...)
|
||||
|
||||
for i = 1, args.n do
|
||||
string = string .. tostring(args[i]) .. "\t"
|
||||
end
|
||||
|
||||
return string .. "\n"
|
||||
end
|
||||
|
||||
function M.split(s, sep)
|
||||
local fields = {}
|
||||
|
||||
local sep = sep or " "
|
||||
local pattern = string.format("([^%s]+)", sep)
|
||||
string.gsub(
|
||||
s,
|
||||
pattern,
|
||||
function(c)
|
||||
fields[#fields + 1] = c
|
||||
end
|
||||
)
|
||||
|
||||
return fields
|
||||
end
|
||||
|
||||
M.open_file = function(filename)
|
||||
vim.api.nvim_command(string.format("e! %s", filename))
|
||||
end
|
||||
|
||||
M.open_file_at = function(filename, line)
|
||||
vim.api.nvim_command(string.format("e! +%s %s", line, filename))
|
||||
end
|
||||
|
||||
function M.exists(var)
|
||||
for k, _ in pairs(_G) do
|
||||
if k == var then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.partial(func, arg)
|
||||
return (function(...)
|
||||
return func(arg, ...)
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,24 @@
|
||||
" built upon popfix api(https://github.com/RishabhRD/popfix)
|
||||
" for parameter references see popfix readme.
|
||||
|
||||
if exists('g:loaded_navigator_lsp') | finish | endif
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if ! exists('g:navigator_lsp_location_opts')
|
||||
let g:navigator_lsp_location_opts = v:null
|
||||
endif
|
||||
|
||||
if ! exists('g:navigator_lsp_symbols_opts')
|
||||
let g:navigator_lsp_symbols_opts = v:null
|
||||
endif
|
||||
|
||||
if ! exists('g:navigator_lsp_codeaction_opts')
|
||||
let g:navigator_lsp_codeaction_opts = v:null
|
||||
endif
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
let g:loaded_navigator_lsp = 1
|
Loading…
Reference in New Issue