diff options
-rw-r--r-- | runtime/doc/lsp.txt | 4 | ||||
-rw-r--r-- | runtime/lua/vim/lsp.lua | 17 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 5 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/callbacks.lua | 10 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/protocol.lua | 26 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 57 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 128 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 2 |
8 files changed, 153 insertions, 96 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d5ed857f32..2f5427f6fc 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -48,6 +48,7 @@ go-to-definition, hover, etc. Example config: > nnoremap <silent> <c-k> <cmd>lua vim.lsp.buf.signature_help()<CR> nnoremap <silent> 1gD <cmd>lua vim.lsp.buf.type_definition()<CR> nnoremap <silent> gr <cmd>lua vim.lsp.buf.references()<CR> + nnoremap <silent> g0 <cmd>lua vim.lsp.buf.document_symbol()<CR> Nvim provides the |vim.lsp.omnifunc| 'omnifunc' handler which allows |i_CTRL-X_CTRL-O| to consume LSP completion. Example config (note the use of @@ -733,6 +734,9 @@ definition() *vim.lsp.buf.definition()* document_highlight() *vim.lsp.buf.document_highlight()* TODO: Documentation +document_symbol() *vim.lsp.buf.document_symbol()* + TODO: Documentation + formatting({options}) *vim.lsp.buf.formatting()* TODO: Documentation diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 71ec3cb6c4..8af20ea1f9 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -101,7 +101,7 @@ local function for_each_buffer_client(bufnr, callback) for client_id in pairs(client_ids) do local client = active_clients[client_id] if client then - callback(client, client_id) + callback(client, client_id, bufnr) end end end @@ -520,23 +520,24 @@ function lsp.start_client(config) end --- Checks capabilities before rpc.request-ing. - function client.request(method, params, callback) + function client.request(method, params, callback, bufnr) if not callback then callback = resolve_callback(method) or error("not found: request callback for client "..client.name) end - local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback) + local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback, bufnr) -- TODO keep these checks or just let it go anyway? if (not client.resolved_capabilities.hover and method == 'textDocument/hover') or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp') or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition') or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation') + or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol') then - callback(unsupported_method(method), method, nil, client_id) + callback(unsupported_method(method), method, nil, client_id, bufnr) return end return rpc.request(method, params, function(err, result) - callback(err, method, result, client_id) + callback(err, method, result, client_id, bufnr) end) end @@ -836,8 +837,8 @@ function lsp.buf_request(bufnr, method, params, callback) callback = { callback, 'f', true }; } local client_request_ids = {} - for_each_buffer_client(bufnr, function(client, client_id) - local request_success, request_id = client.request(method, params, callback) + for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr) + local request_success, request_id = client.request(method, params, callback, resolved_bufnr) -- This could only fail if the client shut down in the time since we looked -- it up and we did the request, which should be rare. @@ -905,7 +906,7 @@ function lsp.buf_notify(bufnr, method, params) method = { method, 's' }; } local resp = false - for_each_buffer_client(bufnr, function(client, _client_id) + for_each_buffer_client(bufnr, function(client, _client_id, _resolved_bufnr) if client.rpc.notify(method, params) then resp = true end end) return resp diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 82aeccd4db..fc9e10cb73 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -138,6 +138,11 @@ function M.references(context) request('textDocument/references', params) end +function M.document_symbol() + local params = { textDocument = util.make_text_document_params() } + request('textDocument/documentSymbol', params) +end + --- Send request to server to resolve document highlights for the --- current text document position. This request can be associated --- to key mapping or to events such as `CursorHold`, eg: diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua index 99093216d9..63b5c4d493 100644 --- a/runtime/lua/vim/lsp/callbacks.lua +++ b/runtime/lua/vim/lsp/callbacks.lua @@ -38,7 +38,13 @@ end M['textDocument/references'] = function(_, _, result) if not result then return end - util.set_qflist(result) + util.set_qflist(util.locations_to_items(result)) +end + +M['textDocument/documentSymbol'] = function(_, _, result, _, bufnr) + if not result or vim.tbl_isempty(result) then return end + + util.set_qflist(util.symbols_to_items(result, bufnr)) api.nvim_command("copen") api.nvim_command("wincmd p") end @@ -97,7 +103,7 @@ local function location_callback(_, method, result) end util.jump_to_location(result[1]) if #result > 1 then - util.set_qflist(result) + util.set_qflist(util.locations_to_items(result)) api.nvim_command("copen") api.nvim_command("wincmd p") end diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index f64b0b50e7..41e8119c8c 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -663,19 +663,19 @@ function protocol.make_client_capabilities() documentHighlight = { dynamicRegistration = false }; - -- documentSymbol = { - -- dynamicRegistration = false; - -- symbolKind = { - -- valueSet = (function() - -- local res = {} - -- for k in pairs(protocol.SymbolKind) do - -- if type(k) == 'string' then table.insert(res, k) end - -- end - -- return res - -- end)(); - -- }; - -- hierarchicalDocumentSymbolSupport = false; - -- }; + documentSymbol = { + dynamicRegistration = false; + symbolKind = { + valueSet = (function() + local res = {} + for k in pairs(protocol.SymbolKind) do + if type(k) == 'number' then table.insert(res, k) end + end + return res + end)(); + }; + hierarchicalDocumentSymbolSupport = true; + }; }; workspace = nil; experimental = nil; diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 5f0fe8ceb4..72c84b8471 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -834,23 +834,60 @@ function M.locations_to_items(locations) return items end --- locations is Location[] --- Only sets for the current window. -function M.set_loclist(locations) +function M.set_loclist(items) vim.fn.setloclist(0, {}, ' ', { title = 'Language Server'; - items = M.locations_to_items(locations); + items = items; }) end --- locations is Location[] -function M.set_qflist(locations) +function M.set_qflist(items) vim.fn.setqflist({}, ' ', { title = 'Language Server'; - items = M.locations_to_items(locations); + items = items; }) end +--- Convert symbols to quickfix list items +--- +--@symbols DocumentSymbol[] or SymbolInformation[] +function M.symbols_to_items(symbols, bufnr) + local function _symbols_to_items(_symbols, _items, _bufnr) + for _, symbol in ipairs(_symbols) do + if symbol.location then -- SymbolInformation type + local range = symbol.location.range + local kind = protocol.SymbolKind[symbol.kind] + table.insert(_items, { + filename = vim.uri_to_fname(symbol.location.uri), + lnum = range.start.line + 1, + col = range.start.character + 1, + kind = kind, + text = '['..kind..'] '..symbol.name, + }) + elseif symbol.range then -- DocumentSymbole type + local kind = protocol.SymbolKind[symbol.kind] + table.insert(_items, { + -- bufnr = _bufnr, + filename = vim.api.nvim_buf_get_name(_bufnr), + lnum = symbol.range.start.line + 1, + col = symbol.range.start.character + 1, + kind = kind, + text = '['..kind..'] '..symbol.name + }) + if symbol.children then + for _, child in ipairs(symbol) do + for _, v in ipairs(_symbols_to_items(child, _items, _bufnr)) do + vim.list_extend(_items, v) + end + end + end + end + end + return _items + end + return _symbols_to_items(symbols, {}, bufnr) +end + -- Remove empty lines from the beginning and end. function M.trim_empty_lines(lines) local start = 1 @@ -903,11 +940,15 @@ function M.make_position_params() local line = api.nvim_buf_get_lines(0, row, row+1, true)[1] col = str_utfindex(line, col) return { - textDocument = { uri = vim.uri_from_bufnr(0) }; + textDocument = M.make_text_document_params(); position = { line = row; character = col; } } end +function M.make_text_document_params() + return { uri = vim.uri_from_bufnr(0) } +end + -- @param buf buffer handle or 0 for current. -- @param row 0-indexed line -- @param col 0-indexed byte offset in line diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 96fd6ac61f..e67be60aa6 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -265,70 +265,70 @@ static struct { const char *name; int canon; } enc_alias_table[] = { - {"ansi", IDX_LATIN_1}, - {"iso-8859-1", IDX_LATIN_1}, - {"latin2", IDX_ISO_2}, - {"latin3", IDX_ISO_3}, - {"latin4", IDX_ISO_4}, - {"cyrillic", IDX_ISO_5}, - {"arabic", IDX_ISO_6}, - {"greek", IDX_ISO_7}, - {"hebrew", IDX_ISO_8}, - {"latin5", IDX_ISO_9}, - {"turkish", IDX_ISO_9}, /* ? */ - {"latin6", IDX_ISO_10}, - {"nordic", IDX_ISO_10}, /* ? */ - {"thai", IDX_ISO_11}, /* ? */ - {"latin7", IDX_ISO_13}, - {"latin8", IDX_ISO_14}, - {"latin9", IDX_ISO_15}, - {"utf8", IDX_UTF8}, - {"unicode", IDX_UCS2}, - {"ucs2", IDX_UCS2}, - {"ucs2be", IDX_UCS2}, - {"ucs-2be", IDX_UCS2}, - {"ucs2le", IDX_UCS2LE}, - {"utf16", IDX_UTF16}, - {"utf16be", IDX_UTF16}, - {"utf-16be", IDX_UTF16}, - {"utf16le", IDX_UTF16LE}, - {"ucs4", IDX_UCS4}, - {"ucs4be", IDX_UCS4}, - {"ucs-4be", IDX_UCS4}, - {"ucs4le", IDX_UCS4LE}, - {"utf32", IDX_UCS4}, - {"utf-32", IDX_UCS4}, - {"utf32be", IDX_UCS4}, - {"utf-32be", IDX_UCS4}, - {"utf32le", IDX_UCS4LE}, - {"utf-32le", IDX_UCS4LE}, - {"932", IDX_CP932}, - {"949", IDX_CP949}, - {"936", IDX_CP936}, - {"gbk", IDX_CP936}, - {"950", IDX_CP950}, - {"eucjp", IDX_EUC_JP}, - {"unix-jis", IDX_EUC_JP}, - {"ujis", IDX_EUC_JP}, - {"shift-jis", IDX_SJIS}, - {"pck", IDX_SJIS}, /* Sun: PCK */ - {"euckr", IDX_EUC_KR}, - {"5601", IDX_EUC_KR}, /* Sun: KS C 5601 */ - {"euccn", IDX_EUC_CN}, - {"gb2312", IDX_EUC_CN}, - {"euctw", IDX_EUC_TW}, - {"japan", IDX_EUC_JP}, - {"korea", IDX_EUC_KR}, - {"prc", IDX_EUC_CN}, - {"zh-cn", IDX_EUC_CN}, - {"chinese", IDX_EUC_CN}, - {"zh-tw", IDX_EUC_TW}, - {"taiwan", IDX_EUC_TW}, - {"cp950", IDX_BIG5}, - {"950", IDX_BIG5}, - {"mac", IDX_MACROMAN}, - {"mac-roman", IDX_MACROMAN}, - {NULL, 0} + { "ansi", IDX_LATIN_1 }, + { "iso-8859-1", IDX_LATIN_1 }, + { "latin2", IDX_ISO_2 }, + { "latin3", IDX_ISO_3 }, + { "latin4", IDX_ISO_4 }, + { "cyrillic", IDX_ISO_5 }, + { "arabic", IDX_ISO_6 }, + { "greek", IDX_ISO_7 }, + { "hebrew", IDX_ISO_8 }, + { "latin5", IDX_ISO_9 }, + { "turkish", IDX_ISO_9 }, // ? + { "latin6", IDX_ISO_10 }, + { "nordic", IDX_ISO_10 }, // ? + { "thai", IDX_ISO_11 }, // ? + { "latin7", IDX_ISO_13 }, + { "latin8", IDX_ISO_14 }, + { "latin9", IDX_ISO_15 }, + { "utf8", IDX_UTF8 }, + { "unicode", IDX_UCS2 }, + { "ucs2", IDX_UCS2 }, + { "ucs2be", IDX_UCS2 }, + { "ucs-2be", IDX_UCS2 }, + { "ucs2le", IDX_UCS2LE }, + { "utf16", IDX_UTF16 }, + { "utf16be", IDX_UTF16 }, + { "utf-16be", IDX_UTF16 }, + { "utf16le", IDX_UTF16LE }, + { "ucs4", IDX_UCS4 }, + { "ucs4be", IDX_UCS4 }, + { "ucs-4be", IDX_UCS4 }, + { "ucs4le", IDX_UCS4LE }, + { "utf32", IDX_UCS4 }, + { "utf-32", IDX_UCS4 }, + { "utf32be", IDX_UCS4 }, + { "utf-32be", IDX_UCS4 }, + { "utf32le", IDX_UCS4LE }, + { "utf-32le", IDX_UCS4LE }, + { "932", IDX_CP932 }, + { "949", IDX_CP949 }, + { "936", IDX_CP936 }, + { "gbk", IDX_CP936 }, + { "950", IDX_CP950 }, + { "eucjp", IDX_EUC_JP }, + { "unix-jis", IDX_EUC_JP }, + { "ujis", IDX_EUC_JP }, + { "shift-jis", IDX_SJIS }, + { "pck", IDX_SJIS }, // Sun: PCK + { "euckr", IDX_EUC_KR }, + { "5601", IDX_EUC_KR }, // Sun: KS C 5601 + { "euccn", IDX_EUC_CN }, + { "gb2312", IDX_EUC_CN }, + { "euctw", IDX_EUC_TW }, + { "japan", IDX_EUC_JP }, + { "korea", IDX_EUC_KR }, + { "prc", IDX_EUC_CN }, + { "zh-cn", IDX_EUC_CN }, + { "chinese", IDX_EUC_CN }, + { "zh-tw", IDX_EUC_TW }, + { "taiwan", IDX_EUC_TW }, + { "cp950", IDX_BIG5 }, + { "950", IDX_BIG5 }, + { "mac", IDX_MACROMAN }, + { "mac-roman", IDX_MACROMAN }, + { NULL, 0 } }; /* diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ba1eb2113e..369b826adf 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -241,7 +241,7 @@ describe('LSP', function() it('should succeed with manual shutdown', function() local expected_callbacks = { - {NIL, "shutdown", {}, 1}; + {NIL, "shutdown", {}, 1, NIL}; {NIL, "test", {}, 1}; } test_rpc_server { |