diff --git a/lua/symbols-outline.lua b/lua/symbols-outline.lua index b712044..bf253d1 100644 --- a/lua/symbols-outline.lua +++ b/lua/symbols-outline.lua @@ -1,197 +1,191 @@ local vim = vim -local parser = require('symbols-outline.parser') -local providers = require('symbols-outline.providers.init') -local ui = require('symbols-outline.ui') -local writer = require('symbols-outline.writer') -local config = require('symbols-outline.config') -local utils = require('symbols-outline.utils.init') -local view = require('symbols-outline.view') +local parser = require 'symbols-outline.parser' +local providers = require 'symbols-outline.providers.init' +local ui = require 'symbols-outline.ui' +local writer = require 'symbols-outline.writer' +local config = require 'symbols-outline.config' +local utils = require 'symbols-outline.utils.init' +local view = require 'symbols-outline.view' local M = {} local function setup_global_autocmd() - if config.options.highlight_hovered_item then - vim.cmd( - "au CursorHold * :lua require('symbols-outline')._highlight_current_item()") - end + if config.options.highlight_hovered_item then + vim.cmd "au CursorHold * :lua require('symbols-outline')._highlight_current_item()" + end end local function setup_buffer_autocmd() - if config.options.auto_preview then - vim.cmd( - "au CursorHold lua require'symbols-outline.preview'.show()") - else - vim.cmd( - "au CursorMoved lua require'symbols-outline.preview'.close()") - end - + if config.options.auto_preview then + vim.cmd "au CursorHold lua require'symbols-outline.preview'.show()" + else + vim.cmd "au CursorMoved lua require'symbols-outline.preview'.close()" + end end ------------------------- -- STATE ------------------------- M.state = { - outline_items = {}, - flattened_outline_items = {}, - outline_win = nil, - outline_buf = nil, - code_win = 0 + outline_items = {}, + flattened_outline_items = {}, + outline_win = nil, + outline_buf = nil, + code_win = 0, } local function wipe_state() - M.state = {outline_items = {}, flattened_outline_items = {}, code_win = 0} + M.state = { outline_items = {}, flattened_outline_items = {}, code_win = 0 } end local function __refresh() - if M.state.outline_buf ~= nil then - local function refresh_handler(response) - if response == nil or type(response) ~= 'table' then - return - end + if M.state.outline_buf ~= nil then + local function refresh_handler(response) + if response == nil or type(response) ~= 'table' then + return + end - local items = parser.parse(response) + local items = parser.parse(response) - M.state.code_win = vim.api.nvim_get_current_win() - M.state.outline_items = items - M.state.flattened_outline_items = parser.flatten(items) + M.state.code_win = vim.api.nvim_get_current_win() + M.state.outline_items = items + M.state.flattened_outline_items = parser.flatten(items) - writer.parse_and_write(M.state.outline_buf, - M.state.flattened_outline_items) - end - - providers.request_symbols(refresh_handler) + writer.parse_and_write(M.state.outline_buf, M.state.flattened_outline_items) end + + providers.request_symbols(refresh_handler) + end end M._refresh = utils.debounce(__refresh, 100) function M._goto_location(change_focus) - local current_line = vim.api.nvim_win_get_cursor(M.state.outline_win)[1] - local node = M.state.flattened_outline_items[current_line] - vim.api.nvim_win_set_cursor(M.state.code_win, - {node.line + 1, node.character}) - if change_focus then vim.fn.win_gotoid(M.state.code_win) end - if config.options.auto_close then M.close_outline() end + local current_line = vim.api.nvim_win_get_cursor(M.state.outline_win)[1] + local node = M.state.flattened_outline_items[current_line] + vim.api.nvim_win_set_cursor(M.state.code_win, { node.line + 1, node.character }) + if change_focus then + vim.fn.win_gotoid(M.state.code_win) + end + if config.options.auto_close then + M.close_outline() + end end function M._highlight_current_item(winnr) - local has_provider = providers.has_provider() + local has_provider = providers.has_provider() - local is_current_buffer_the_outline = - M.state.outline_buf == vim.api.nvim_get_current_buf() + local is_current_buffer_the_outline = M.state.outline_buf == vim.api.nvim_get_current_buf() - local doesnt_have_outline_buf = not M.state.outline_buf + local doesnt_have_outline_buf = not M.state.outline_buf - local should_exit = (not has_provider) or - doesnt_have_outline_buf or - is_current_buffer_the_outline + local should_exit = not has_provider or doesnt_have_outline_buf or is_current_buffer_the_outline - -- Make a special case if we have a window number - -- Because we might use this to manually focus so we dont want to quit this - -- function - if winnr then should_exit = false end + -- Make a special case if we have a window number + -- Because we might use this to manually focus so we dont want to quit this + -- function + if winnr then + should_exit = false + end - if should_exit then return end + if should_exit then + return + end - local win = winnr or vim.api.nvim_get_current_win() + local win = winnr or vim.api.nvim_get_current_win() - local hovered_line = vim.api.nvim_win_get_cursor(win)[1] - 1 + local hovered_line = vim.api.nvim_win_get_cursor(win)[1] - 1 - local nodes = {} - for index, value in ipairs(M.state.flattened_outline_items) do - if value.line == hovered_line or - (hovered_line > value.range_start and hovered_line < value.range_end) then - value.line_in_outline = index - table.insert(nodes, value) - end + local nodes = {} + for index, value in ipairs(M.state.flattened_outline_items) do + if value.line == hovered_line or (hovered_line > value.range_start and hovered_line < value.range_end) then + value.line_in_outline = index + table.insert(nodes, value) end + end - -- clear old highlight - ui.clear_hover_highlight(M.state.outline_buf) - for _, value in ipairs(nodes) do - ui.add_hover_highlight(M.state.outline_buf, value.line_in_outline - 1, - value.depth * 2) - vim.api.nvim_win_set_cursor(M.state.outline_win, - {value.line_in_outline, 1}) - end + -- clear old highlight + ui.clear_hover_highlight(M.state.outline_buf) + for _, value in ipairs(nodes) do + ui.add_hover_highlight(M.state.outline_buf, value.line_in_outline - 1, value.depth * 2) + vim.api.nvim_win_set_cursor(M.state.outline_win, { value.line_in_outline, 1 }) + end end local function setup_keymaps(bufnr) - local map = function (...) - utils.nmap(bufnr, ...) - end - -- goto_location of symbol and focus that window - map(config.options.keymaps.goto_location, - ":lua require('symbols-outline')._goto_location(true)") - -- goto_location of symbol but stay in outline - map(config.options.keymaps.focus_location, - ":lua require('symbols-outline')._goto_location(false)") - -- hover symbol - map(config.options.keymaps.hover_symbol, - ":lua require('symbols-outline.hover').show_hover()") - -- preview symbol - map(config.options.keymaps.toggle_preview, - ":lua require('symbols-outline.preview').toggle()") - -- rename symbol - map(config.options.keymaps.rename_symbol, - ":lua require('symbols-outline.rename').rename()") - -- code actions - map(config.options.keymaps.code_actions, - ":lua require('symbols-outline.code_action').show_code_actions()") - -- show help - map(config.options.keymaps.show_help, - ":lua require('symbols-outline.config').show_help()") - -- close outline - map(config.options.keymaps.close, ":bw!") + local map = function(...) + utils.nmap(bufnr, ...) + end + -- goto_location of symbol and focus that window + map(config.options.keymaps.goto_location, ":lua require('symbols-outline')._goto_location(true)") + -- goto_location of symbol but stay in outline + map(config.options.keymaps.focus_location, ":lua require('symbols-outline')._goto_location(false)") + -- hover symbol + map(config.options.keymaps.hover_symbol, ":lua require('symbols-outline.hover').show_hover()") + -- preview symbol + map(config.options.keymaps.toggle_preview, ":lua require('symbols-outline.preview').toggle()") + -- rename symbol + map(config.options.keymaps.rename_symbol, ":lua require('symbols-outline.rename').rename()") + -- code actions + map(config.options.keymaps.code_actions, ":lua require('symbols-outline.code_action').show_code_actions()") + -- show help + map(config.options.keymaps.show_help, ":lua require('symbols-outline.config').show_help()") + -- close outline + map(config.options.keymaps.close, ':bw!') end local function handler(response) - if response == nil or type(response) ~= 'table' then return end + if response == nil or type(response) ~= 'table' then + return + end - M.state.code_win = vim.api.nvim_get_current_win() + M.state.code_win = vim.api.nvim_get_current_win() - M.state.outline_buf, M.state.outline_win = view.setup_view() - -- clear state when buffer is closed - vim.api.nvim_buf_attach(M.state.outline_buf, false, - {on_detach = function(_, _) wipe_state() end}) - setup_keymaps(M.state.outline_buf) - setup_buffer_autocmd() + M.state.outline_buf, M.state.outline_win = view.setup_view() + -- clear state when buffer is closed + vim.api.nvim_buf_attach(M.state.outline_buf, false, { + on_detach = function(_, _) + wipe_state() + end, + }) + setup_keymaps(M.state.outline_buf) + setup_buffer_autocmd() - local items = parser.parse(response) + local items = parser.parse(response) - M.state.outline_items = items - M.state.flattened_outline_items = parser.flatten(items) + M.state.outline_items = items + M.state.flattened_outline_items = parser.flatten(items) - writer.parse_and_write(M.state.outline_buf, M.state.flattened_outline_items) - ui.setup_highlights() + writer.parse_and_write(M.state.outline_buf, M.state.flattened_outline_items) + ui.setup_highlights() - M._highlight_current_item(M.state.code_win) + M._highlight_current_item(M.state.code_win) end function M.toggle_outline() - if M.state.outline_buf == nil then - M.open_outline() - else - M.close_outline() - end + if M.state.outline_buf == nil then + M.open_outline() + else + M.close_outline() + end end function M.open_outline() - if M.state.outline_buf == nil then - providers.request_symbols(handler) - end + if M.state.outline_buf == nil then + providers.request_symbols(handler) + end end function M.close_outline() - if M.state.outline_buf then - vim.api.nvim_win_close(M.state.outline_win, true) - end + if M.state.outline_buf then + vim.api.nvim_win_close(M.state.outline_win, true) + end end function M.setup(opts) - config.setup(opts) - setup_global_autocmd() + config.setup(opts) + setup_global_autocmd() end return M diff --git a/lua/symbols-outline/code_action.lua b/lua/symbols-outline/code_action.lua index 33c3213..4c7f992 100644 --- a/lua/symbols-outline/code_action.lua +++ b/lua/symbols-outline/code_action.lua @@ -1,32 +1,31 @@ local vim = vim -local main = require('symbols-outline') +local main = require 'symbols-outline' local buf_request = require('symbols-outline.utils.lsp_utils').request local M = {} local function get_action_params(node, winnr) - local bufnr = vim.api.nvim_win_get_buf(winnr) - local fn = "file://" .. vim.api.nvim_buf_get_name(bufnr) + local bufnr = vim.api.nvim_win_get_buf(winnr) + local fn = 'file://' .. vim.api.nvim_buf_get_name(bufnr) - local pos = {line = node.line, character = node.character} - local diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr, node.line) - return { - textDocument = {uri = fn}, - range = {start = pos, ["end"] = pos}, - context = {diagnostics = diagnostics}, - bufnr = bufnr - } + local pos = { line = node.line, character = node.character } + local diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr, node.line) + return { + textDocument = { uri = fn }, + range = { start = pos, ['end'] = pos }, + context = { diagnostics = diagnostics }, + bufnr = bufnr, + } end function M.show_code_actions() - local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] - local node = main.state.flattened_outline_items[current_line] + local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] + local node = main.state.flattened_outline_items[current_line] - local params = get_action_params(node, main.state.code_win) + local params = get_action_params(node, main.state.code_win) - buf_request(params.bufnr, "textDocument/codeAction", params, - vim.lsp.handlers["textDocument/codeAction"]) + buf_request(params.bufnr, 'textDocument/codeAction', params, vim.lsp.handlers['textDocument/codeAction']) end return M diff --git a/lua/symbols-outline/config.lua b/lua/symbols-outline/config.lua index ab20ea9..d09e64a 100644 --- a/lua/symbols-outline/config.lua +++ b/lua/symbols-outline/config.lua @@ -3,72 +3,72 @@ local vim = vim local M = {} M.defaults = { - highlight_hovered_item = true, - show_guides = true, - position = 'right', - border = 'single', - relative_width = true, - width = 25, - auto_close = false, - auto_preview = true, - show_numbers = false, - show_relative_numbers = false, - show_symbol_details = true, - preview_bg_highlight = 'Pmenu', - keymaps = { -- These keymaps can be a string or a table for multiple keys - close = {"", "q"}, - goto_location = "", - focus_location = "o", - hover_symbol = "", - toggle_preview = "K", - rename_symbol = "r", - code_actions = "a", - show_help = "?" - }, - lsp_blacklist = {}, - symbol_blacklist = {}, - symbols = { - File = {icon = "", hl = "TSURI"}, - Module = {icon = "", hl = "TSNamespace"}, - Namespace = {icon = "", hl = "TSNamespace"}, - Package = {icon = "", hl = "TSNamespace"}, - Class = {icon = "𝓒", hl = "TSType"}, - Method = {icon = "ƒ", hl = "TSMethod"}, - Property = {icon = "", hl = "TSMethod"}, - Field = {icon = "", hl = "TSField"}, - Constructor = {icon = "", hl = "TSConstructor"}, - Enum = {icon = "ℰ", hl = "TSType"}, - Interface = {icon = "ﰮ", hl = "TSType"}, - Function = {icon = "", hl = "TSFunction"}, - Variable = {icon = "", hl = "TSConstant"}, - Constant = {icon = "", hl = "TSConstant"}, - String = {icon = "𝓐", hl = "TSString"}, - Number = {icon = "#", hl = "TSNumber"}, - Boolean = {icon = "⊨", hl = "TSBoolean"}, - Array = {icon = "", hl = "TSConstant"}, - Object = {icon = "⦿", hl = "TSType"}, - Key = {icon = "🔐", hl = "TSType"}, - Null = {icon = "NULL", hl = "TSType"}, - EnumMember = {icon = "", hl = "TSField"}, - Struct = {icon = "𝓢", hl = "TSType"}, - Event = {icon = "🗲", hl = "TSType"}, - Operator = {icon = "+", hl = "TSOperator"}, - TypeParameter = {icon = "𝙏", hl = "TSParameter"} - } + highlight_hovered_item = true, + show_guides = true, + position = 'right', + border = 'single', + relative_width = true, + width = 25, + auto_close = false, + auto_preview = true, + show_numbers = false, + show_relative_numbers = false, + show_symbol_details = true, + preview_bg_highlight = 'Pmenu', + keymaps = { -- These keymaps can be a string or a table for multiple keys + close = { '', 'q' }, + goto_location = '', + focus_location = 'o', + hover_symbol = '', + toggle_preview = 'K', + rename_symbol = 'r', + code_actions = 'a', + show_help = '?', + }, + lsp_blacklist = {}, + symbol_blacklist = {}, + symbols = { + File = { icon = '', hl = 'TSURI' }, + Module = { icon = '', hl = 'TSNamespace' }, + Namespace = { icon = '', hl = 'TSNamespace' }, + Package = { icon = '', hl = 'TSNamespace' }, + Class = { icon = '𝓒', hl = 'TSType' }, + Method = { icon = 'ƒ', hl = 'TSMethod' }, + Property = { icon = '', hl = 'TSMethod' }, + Field = { icon = '', hl = 'TSField' }, + Constructor = { icon = '', hl = 'TSConstructor' }, + Enum = { icon = 'ℰ', hl = 'TSType' }, + Interface = { icon = 'ﰮ', hl = 'TSType' }, + Function = { icon = '', hl = 'TSFunction' }, + Variable = { icon = '', hl = 'TSConstant' }, + Constant = { icon = '', hl = 'TSConstant' }, + String = { icon = '𝓐', hl = 'TSString' }, + Number = { icon = '#', hl = 'TSNumber' }, + Boolean = { icon = '⊨', hl = 'TSBoolean' }, + Array = { icon = '', hl = 'TSConstant' }, + Object = { icon = '⦿', hl = 'TSType' }, + Key = { icon = '🔐', hl = 'TSType' }, + Null = { icon = 'NULL', hl = 'TSType' }, + EnumMember = { icon = '', hl = 'TSField' }, + Struct = { icon = '𝓢', hl = 'TSType' }, + Event = { icon = '🗲', hl = 'TSType' }, + Operator = { icon = '+', hl = 'TSOperator' }, + TypeParameter = { icon = '𝙏', hl = 'TSParameter' }, + }, } M.options = {} function M.has_numbers() - return M.options.show_numbers or M.options.show_relative_numbers + return M.options.show_numbers or M.options.show_relative_numbers end function M.get_position_navigation_direction() - if M.options.position == 'left' then - return 'h' - else - return 'l' - end + if M.options.position == 'left' then + return 'h' + else + return 'l' + end end function M.get_window_width() @@ -79,40 +79,47 @@ function M.get_window_width() end end - function M.get_split_command() - if M.options.position == 'left' then - return "topleft vs" - else - return "botright vs" - end + if M.options.position == 'left' then + return 'topleft vs' + else + return 'botright vs' + end end local function has_value(tab, val) - for _, value in ipairs(tab) do if value == val then return true end end + for _, value in ipairs(tab) do + if value == val then + return true + end + end - return false + return false end function M.is_symbol_blacklisted(kind) - if kind == nil then return false end - return has_value(M.options.symbol_blacklist, kind) + if kind == nil then + return false + end + return has_value(M.options.symbol_blacklist, kind) end function M.is_client_blacklisted(client_id) - local client = vim.lsp.get_client_by_id(client_id) - if not client then return false end - return has_value(M.options.lsp_blacklist, client.name) + local client = vim.lsp.get_client_by_id(client_id) + if not client then + return false + end + return has_value(M.options.lsp_blacklist, client.name) end function M.show_help() - print "Current keymaps:" - print(vim.inspect(M.options.keymaps)) + print 'Current keymaps:' + print(vim.inspect(M.options.keymaps)) end function M.setup(options) - vim.g.symbols_outline_loaded = 1 - M.options = vim.tbl_deep_extend("force", {}, M.defaults, options or {}) + vim.g.symbols_outline_loaded = 1 + M.options = vim.tbl_deep_extend('force', {}, M.defaults, options or {}) end return M diff --git a/lua/symbols-outline/hover.lua b/lua/symbols-outline/hover.lua index 259668f..52d3b34 100644 --- a/lua/symbols-outline/hover.lua +++ b/lua/symbols-outline/hover.lua @@ -1,45 +1,42 @@ local vim = vim -local main = require('symbols-outline') +local main = require 'symbols-outline' local util = vim.lsp.util local buf_request = require('symbols-outline.utils.lsp_utils').request local M = {} local function get_hover_params(node, winnr) - local bufnr = vim.api.nvim_win_get_buf(winnr) - local fn = vim.uri_from_bufnr(bufnr) + local bufnr = vim.api.nvim_win_get_buf(winnr) + local fn = vim.uri_from_bufnr(bufnr) - return { - textDocument = {uri = fn}, - position = {line = node.line, character = node.character}, - bufnr = bufnr - } + return { + textDocument = { uri = fn }, + position = { line = node.line, character = node.character }, + bufnr = bufnr, + } end -- handler yoinked from the default implementation function M.show_hover() - local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] - local node = main.state.flattened_outline_items[current_line] + local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] + local node = main.state.flattened_outline_items[current_line] - local hover_params = get_hover_params(node, main.state.code_win) + local hover_params = get_hover_params(node, main.state.code_win) - buf_request(hover_params.bufnr, "textDocument/hover", hover_params, - function(_, result, _, config) - - if not (result and result.contents) then - -- return { 'No information available' } - return - end - local markdown_lines = util.convert_input_to_markdown_lines( - result.contents) - markdown_lines = util.trim_empty_lines(markdown_lines) - if vim.tbl_isempty(markdown_lines) then - -- return { 'No information available' } - return - end - return util.open_floating_preview(markdown_lines, "markdown", config) - end) + buf_request(hover_params.bufnr, 'textDocument/hover', hover_params, function(_, result, _, config) + if not (result and result.contents) then + -- return { 'No information available' } + return + end + local markdown_lines = util.convert_input_to_markdown_lines(result.contents) + markdown_lines = util.trim_empty_lines(markdown_lines) + if vim.tbl_isempty(markdown_lines) then + -- return { 'No information available' } + return + end + return util.open_floating_preview(markdown_lines, 'markdown', config) + end) end return M diff --git a/lua/symbols-outline/markdown.lua b/lua/symbols-outline/markdown.lua index 5b60686..cd909fc 100644 --- a/lua/symbols-outline/markdown.lua +++ b/lua/symbols-outline/markdown.lua @@ -6,63 +6,63 @@ local M = {} -- Note that the headings won't have any hierarchy (as of now). ---@return table function M.handle_markdown() - local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) - local level_symbols = {{children = {}}} - local max_level = 1 - local is_inside_code_block = false + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + local level_symbols = { { children = {} } } + local max_level = 1 + local is_inside_code_block = false - for line, value in ipairs(lines) do - if string.find(value, "^```") then - is_inside_code_block = not is_inside_code_block - end - - header, title = string.match(value, "^(#+)%s+(.*)$") - if header and not is_inside_code_block then - depth = #header + 1 - - for i = depth - 1, 1, -1 do - if level_symbols[i] ~= nil then - parent = level_symbols[i].children - break - end - end - - for i = depth, max_level do - if level_symbols[i] ~= nil then - level_symbols[i].selectionRange["end"].line = line - 1 - level_symbols[i].range["end"].line = line - 1 - level_symbols[i] = nil - end - end - max_level = depth - - entry = { - kind = 13, - name = title, - selectionRange = { - start = {character = 1, line = line - 1}, - ["end"] = {character = 1, line = line - 1} - }, - range = { - start = {character = 1, line = line - 1}, - ["end"] = {character = 1, line = line - 1} - }, - children = {}, - } - - parent[#parent + 1] = entry - level_symbols[depth] = entry - end + for line, value in ipairs(lines) do + if string.find(value, '^```') then + is_inside_code_block = not is_inside_code_block end - for i = 2, max_level do + header, title = string.match(value, '^(#+)%s+(.*)$') + if header and not is_inside_code_block then + depth = #header + 1 + + for i = depth - 1, 1, -1 do if level_symbols[i] ~= nil then - level_symbols[i].selectionRange["end"].line = #lines - level_symbols[i].range["end"].line = #lines + parent = level_symbols[i].children + break end - end + end - return {[1000000]={result=level_symbols[1].children}} + for i = depth, max_level do + if level_symbols[i] ~= nil then + level_symbols[i].selectionRange['end'].line = line - 1 + level_symbols[i].range['end'].line = line - 1 + level_symbols[i] = nil + end + end + max_level = depth + + entry = { + kind = 13, + name = title, + selectionRange = { + start = { character = 1, line = line - 1 }, + ['end'] = { character = 1, line = line - 1 }, + }, + range = { + start = { character = 1, line = line - 1 }, + ['end'] = { character = 1, line = line - 1 }, + }, + children = {}, + } + + parent[#parent + 1] = entry + level_symbols[depth] = entry + end + end + + for i = 2, max_level do + if level_symbols[i] ~= nil then + level_symbols[i].selectionRange['end'].line = #lines + level_symbols[i].range['end'].line = #lines + end + end + + return { [1000000] = { result = level_symbols[1].children } } end return M diff --git a/lua/symbols-outline/parser.lua b/lua/symbols-outline/parser.lua index 0d4f5d4..7b3e510 100644 --- a/lua/symbols-outline/parser.lua +++ b/lua/symbols-outline/parser.lua @@ -1,14 +1,16 @@ -local symbols = require('symbols-outline.symbols') -local ui = require('symbols-outline.ui') -local config = require('symbols-outline.config') +local symbols = require 'symbols-outline.symbols' +local ui = require 'symbols-outline.ui' +local config = require 'symbols-outline.config' local M = {} -- copies an array and returns it because lua usually does references local function array_copy(t) - local ret = {} - for _, value in ipairs(t) do table.insert(ret, value) end - return ret + local ret = {} + for _, value in ipairs(t) do + table.insert(ret, value) + end + return ret end ---Parses result from LSP into a table of symbols @@ -17,201 +19,214 @@ end ---@param hierarchy table A table of booleans which tells if a symbols parent was the last in its group. ---@return table local function parse_result(result, depth, hierarchy) - local ret = {} + local ret = {} - for index, value in pairs(result) do - if not config.is_symbol_blacklisted(symbols.kinds[value.kind]) then - -- the hierarchy is basically a table of booleans which tells whether - -- the parent was the last in its group or not - local hir = hierarchy or {} - -- how many parents this node has, 1 is the lowest value because its - -- easier to work it - local level = depth or 1 - -- whether this node is the last in its group - local isLast = index == #result + for index, value in pairs(result) do + if not config.is_symbol_blacklisted(symbols.kinds[value.kind]) then + -- the hierarchy is basically a table of booleans which tells whether + -- the parent was the last in its group or not + local hir = hierarchy or {} + -- how many parents this node has, 1 is the lowest value because its + -- easier to work it + local level = depth or 1 + -- whether this node is the last in its group + local isLast = index == #result - local children = nil - if value.children ~= nil then - -- copy by value because we dont want it messing with the hir table - local child_hir = array_copy(hir) - table.insert(child_hir, isLast) - children = parse_result(value.children, level + 1, child_hir) - end + local children = nil + if value.children ~= nil then + -- copy by value because we dont want it messing with the hir table + local child_hir = array_copy(hir) + table.insert(child_hir, isLast) + children = parse_result(value.children, level + 1, child_hir) + end - -- support SymbolInformation[] - -- https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol - local selectionRange = value.selectionRange - if value.selectionRange == nil then - selectionRange = value.location.range - end + -- support SymbolInformation[] + -- https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol + local selectionRange = value.selectionRange + if value.selectionRange == nil then + selectionRange = value.location.range + end - local range = value.range - if value.range == nil then range = value.location.range end + local range = value.range + if value.range == nil then + range = value.location.range + end - table.insert(ret, { - deprecated = value.deprecated, - kind = value.kind, - icon = symbols.icon_from_kind(value.kind), - name = value.name or value.text, - detail = value.detail, - line = selectionRange.start.line, - character = selectionRange.start.character, - range_start = range.start.line, - range_end = range["end"].line, - children = children, - depth = level, - isLast = isLast, - hierarchy = hir - }); - end + table.insert(ret, { + deprecated = value.deprecated, + kind = value.kind, + icon = symbols.icon_from_kind(value.kind), + name = value.name or value.text, + detail = value.detail, + line = selectionRange.start.line, + character = selectionRange.start.character, + range_start = range.start.line, + range_end = range['end'].line, + children = children, + depth = level, + isLast = isLast, + hierarchy = hir, + }) end - return ret + end + return ret end ---Sorts the result from LSP by where the symbols start. ---@param result table Result containing symbols returned from textDocument/documentSymbol ---@return table local function sort_result(result) - ---Returns the start location for a symbol, or nil if not found. - ---@param item table The symbol. - ---@return table|nil - local function get_range_start(item) - if item.location ~= nil then - return item.location.range.start - elseif item.range ~= nil then - return item.range.start - else - return nil - end + ---Returns the start location for a symbol, or nil if not found. + ---@param item table The symbol. + ---@return table|nil + local function get_range_start(item) + if item.location ~= nil then + return item.location.range.start + elseif item.range ~= nil then + return item.range.start + else + return nil + end + end + + table.sort(result, function(a, b) + local a_start = get_range_start(a) + local b_start = get_range_start(b) + + -- if they both are equal, a should be before b + if a_start == nil and b_start == nil then + return false end - table.sort(result, function(a, b) - local a_start = get_range_start(a) - local b_start = get_range_start(b) + -- those with no start go first + if a_start == nil then + return true + end + if b_start == nil then + return false + end - -- if they both are equal, a should be before b - if a_start == nil and b_start == nil then return false end + -- first try to sort by line. If lines are equal, sort by character instead + if a_start.line ~= b_start.line then + return a_start.line < b_start.line + else + return a_start.character < b_start.character + end + end) - -- those with no start go first - if a_start == nil then return true end - if b_start == nil then return false end - - -- first try to sort by line. If lines are equal, sort by character instead - if a_start.line ~= b_start.line then - return a_start.line < b_start.line - else - return a_start.character < b_start.character - end - end) - - return result + return result end ---Parses the response from lsp request 'textDocument/documentSymbol' using buf_request_all ---@param response table The result from buf_request_all ---@return table outline items function M.parse(response) - local all_results = {} + local all_results = {} - -- flatten results to one giant table of symbols - for client_id, client_response in pairs(response) do - if config.is_client_blacklisted(client_id) then - print('skipping client ' .. client_id) - goto continue - end - - local result = client_response['result'] - if result == nil or type(result) ~= 'table' then goto continue end - - for _, value in pairs(result) do table.insert(all_results, value) end - - ::continue:: + -- flatten results to one giant table of symbols + for client_id, client_response in pairs(response) do + if config.is_client_blacklisted(client_id) then + print('skipping client ' .. client_id) + goto continue end - local sorted = sort_result(all_results) + local result = client_response['result'] + if result == nil or type(result) ~= 'table' then goto continue end - return parse_result(sorted) + for _, value in pairs(result) do + table.insert(all_results, value) + end + + ::continue:: + end + + local sorted = sort_result(all_results) + + return parse_result(sorted) end function M.flatten(outline_items) - local ret = {} - for _, value in ipairs(outline_items) do - table.insert(ret, value) - if value.children ~= nil then - local inner = M.flatten(value.children) - for _, value_inner in ipairs(inner) do - table.insert(ret, value_inner) - end - end + local ret = {} + for _, value in ipairs(outline_items) do + table.insert(ret, value) + if value.children ~= nil then + local inner = M.flatten(value.children) + for _, value_inner in ipairs(inner) do + table.insert(ret, value_inner) + end end - return ret + end + return ret end local function table_to_str(t) - local ret = "" - for _, value in ipairs(t) do ret = ret .. tostring(value) end - return ret + local ret = '' + for _, value in ipairs(t) do + ret = ret .. tostring(value) + end + return ret end local function str_to_table(str) - local t = {} - for i = 1, #str do t[i] = str:sub(i, i) end - return t + local t = {} + for i = 1, #str do + t[i] = str:sub(i, i) + end + return t end function M.get_lines(flattened_outline_items) - local lines = {} - local hl_info = {} - for _, value in ipairs(flattened_outline_items) do - local line = str_to_table(string.rep(" ", value.depth)) + local lines = {} + local hl_info = {} + for _, value in ipairs(flattened_outline_items) do + local line = str_to_table(string.rep(' ', value.depth)) - if config.options.show_guides then - -- makes the guides - for index, _ in ipairs(line) do - -- all items start with a space (or two) - if index == 1 then - line[index] = " " - -- if index is last, add a bottom marker if current item is last, - -- else add a middle marker - elseif index == #line then - if value.isLast then - line[index] = ui.markers.bottom - else - line[index] = ui.markers.middle - end - -- else if the parent was not the last in its group, add a - -- vertical marker because there are items under us and we need - -- to point to those - elseif not value.hierarchy[index] then - line[index] = ui.markers.vertical - end - end + if config.options.show_guides then + -- makes the guides + for index, _ in ipairs(line) do + -- all items start with a space (or two) + if index == 1 then + line[index] = ' ' + -- if index is last, add a bottom marker if current item is last, + -- else add a middle marker + elseif index == #line then + if value.isLast then + line[index] = ui.markers.bottom + else + line[index] = ui.markers.middle + end + -- else if the parent was not the last in its group, add a + -- vertical marker because there are items under us and we need + -- to point to those + elseif not value.hierarchy[index] then + line[index] = ui.markers.vertical end - - local final_prefix = {} - -- Add 1 space between the guides - for _, v in ipairs(line) do - table.insert(final_prefix, v) - table.insert(final_prefix, " ") - end - - local string_prefix = table_to_str(final_prefix) - local hl_start = #string_prefix - local hl_end = #string_prefix + #value.icon - table.insert(lines, string_prefix .. value.icon .. " " .. - value.name) - hl_type = config.options.symbols[symbols.kinds[value.kind]].hl - table.insert(hl_info, {hl_start, hl_end, hl_type}) + end end - return lines, hl_info + + local final_prefix = {} + -- Add 1 space between the guides + for _, v in ipairs(line) do + table.insert(final_prefix, v) + table.insert(final_prefix, ' ') + end + + local string_prefix = table_to_str(final_prefix) + local hl_start = #string_prefix + local hl_end = #string_prefix + #value.icon + table.insert(lines, string_prefix .. value.icon .. ' ' .. value.name) + hl_type = config.options.symbols[symbols.kinds[value.kind]].hl + table.insert(hl_info, { hl_start, hl_end, hl_type }) + end + return lines, hl_info end function M.get_details(flattened_outline_items) - local lines = {} - for _, value in ipairs(flattened_outline_items) do - table.insert(lines, value.detail or "") - end - return lines + local lines = {} + for _, value in ipairs(flattened_outline_items) do + table.insert(lines, value.detail or '') + end + return lines end return M diff --git a/lua/symbols-outline/preview.lua b/lua/symbols-outline/preview.lua index cd7d69b..9b9a28b 100644 --- a/lua/symbols-outline/preview.lua +++ b/lua/symbols-outline/preview.lua @@ -1,236 +1,236 @@ local vim = vim -local main = require("symbols-outline") -local config = require("symbols-outline.config") -local buf_request = require("symbols-outline.utils.lsp_utils").request +local main = require 'symbols-outline' +local config = require 'symbols-outline.config' +local buf_request = require('symbols-outline.utils.lsp_utils').request local M = {} local state = { - preview_buf = nil, - preview_win = nil, - hover_buf = nil, - hover_win = nil, + preview_buf = nil, + preview_win = nil, + hover_buf = nil, + hover_win = nil, } local function is_current_win_outline() - local curwin = vim.api.nvim_get_current_win() - return curwin == main.state.outline_win + local curwin = vim.api.nvim_get_current_win() + return curwin == main.state.outline_win end local function has_code_win() - local isWinValid = vim.api.nvim_win_is_valid(main.state.code_win) - if not isWinValid then - return false - end - local bufnr = vim.api.nvim_win_get_buf(main.state.code_win) - local isBufValid = vim.api.nvim_buf_is_valid(bufnr) - return isBufValid + local isWinValid = vim.api.nvim_win_is_valid(main.state.code_win) + if not isWinValid then + return false + end + local bufnr = vim.api.nvim_win_get_buf(main.state.code_win) + local isBufValid = vim.api.nvim_buf_is_valid(bufnr) + return isBufValid end local function get_offset() - local outline_winnr = main.state.outline_win - local width = 53 - local height = 0 + local outline_winnr = main.state.outline_win + local width = 53 + local height = 0 - if config.has_numbers() then - width = width + 4 - end + if config.has_numbers() then + width = width + 4 + end - if config.options.position == "right" then - width = 0 - width - else - width = vim.api.nvim_win_get_width(outline_winnr) + 1 - end - return { height, width } + if config.options.position == 'right' then + width = 0 - width + else + width = vim.api.nvim_win_get_width(outline_winnr) + 1 + end + return { height, width } end local function get_height() - local uis = vim.api.nvim_list_uis() - return math.ceil(uis[1].height / 3) + local uis = vim.api.nvim_list_uis() + return math.ceil(uis[1].height / 3) end local function get_hovered_node() - local hovered_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] - local node = main.state.flattened_outline_items[hovered_line] - return node + local hovered_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] + local node = main.state.flattened_outline_items[hovered_line] + return node end local function update_preview(code_buf) - code_buf = code_buf or vim.api.nvim_win_get_buf(main.state.code_win) + code_buf = code_buf or vim.api.nvim_win_get_buf(main.state.code_win) - local node = get_hovered_node() - if not node then - return - end - local lines = vim.api.nvim_buf_get_lines(code_buf, 0, -1, false) + local node = get_hovered_node() + if not node then + return + end + local lines = vim.api.nvim_buf_get_lines(code_buf, 0, -1, false) - if state.preview_buf ~= nil then - vim.api.nvim_buf_set_lines(state.preview_buf, 0, -1, 0, lines) - vim.api.nvim_win_set_cursor(state.preview_win, { node.line + 1, node.character }) - end + if state.preview_buf ~= nil then + vim.api.nvim_buf_set_lines(state.preview_buf, 0, -1, 0, lines) + vim.api.nvim_win_set_cursor(state.preview_win, { node.line + 1, node.character }) + end end local function setup_preview_buf() - local code_buf = vim.api.nvim_win_get_buf(main.state.code_win) - local ft = vim.api.nvim_buf_get_option(code_buf, "filetype") + local code_buf = vim.api.nvim_win_get_buf(main.state.code_win) + local ft = vim.api.nvim_buf_get_option(code_buf, 'filetype') - local function treesitter_attach() - local ts_highlight = require("nvim-treesitter.highlight") + local function treesitter_attach() + local ts_highlight = require 'nvim-treesitter.highlight' - ts_highlight.attach(state.preview_buf, ft) - end + ts_highlight.attach(state.preview_buf, ft) + end - -- user might not have tree sitter installed - pcall(treesitter_attach) + -- user might not have tree sitter installed + pcall(treesitter_attach) - vim.api.nvim_buf_set_option(state.preview_buf, "syntax", ft) - vim.api.nvim_buf_set_option(state.preview_buf, "bufhidden", "delete") - vim.api.nvim_win_set_option(state.preview_win, "cursorline", true) - update_preview(code_buf) + vim.api.nvim_buf_set_option(state.preview_buf, 'syntax', ft) + vim.api.nvim_buf_set_option(state.preview_buf, 'bufhidden', 'delete') + vim.api.nvim_win_set_option(state.preview_win, 'cursorline', true) + update_preview(code_buf) end local function get_hover_params(node, winnr) - local bufnr = vim.api.nvim_win_get_buf(winnr) - local uri = vim.uri_from_bufnr(bufnr) + local bufnr = vim.api.nvim_win_get_buf(winnr) + local uri = vim.uri_from_bufnr(bufnr) - return { - textDocument = { uri = uri }, - position = { line = node.line, character = node.character }, - bufnr = bufnr, - } + return { + textDocument = { uri = uri }, + position = { line = node.line, character = node.character }, + bufnr = bufnr, + } end local function update_hover() - if not has_code_win() then - return - end + if not has_code_win() then + return + end - local node = get_hovered_node() - if not node then - return - end + local node = get_hovered_node() + if not node then + return + end - local provider = _G._symbols_outline_current_provider - local params = get_hover_params(node, main.state.code_win) + local provider = _G._symbols_outline_current_provider + local params = get_hover_params(node, main.state.code_win) - provider.hover_info(params.bufnr, params, function(err, result) - if err then - print(vim.inspect(err)) - end - local markdown_lines = {} - if result ~= nil then - markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents) - end - markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines) - if vim.tbl_isempty(markdown_lines) then - markdown_lines = { "###No info available!" } - end + provider.hover_info(params.bufnr, params, function(err, result) + if err then + print(vim.inspect(err)) + end + local markdown_lines = {} + if result ~= nil then + markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents) + end + markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines) + if vim.tbl_isempty(markdown_lines) then + markdown_lines = { '###No info available!' } + end - markdown_lines = vim.lsp.util.stylize_markdown(state.hover_buf, markdown_lines, {}) + markdown_lines = vim.lsp.util.stylize_markdown(state.hover_buf, markdown_lines, {}) - if state.hover_buf ~= nil then - vim.api.nvim_buf_set_lines(state.hover_buf, 0, -1, 0, markdown_lines) - end - end) + if state.hover_buf ~= nil then + vim.api.nvim_buf_set_lines(state.hover_buf, 0, -1, 0, markdown_lines) + end + end) end local function setup_hover_buf() - if not has_code_win() then - return - end - local code_buf = vim.api.nvim_win_get_buf(main.state.code_win) - local ft = vim.api.nvim_buf_get_option(code_buf, "filetype") - vim.api.nvim_buf_set_option(state.hover_buf, "syntax", ft) - vim.api.nvim_buf_set_option(state.hover_buf, "bufhidden", "delete") - vim.api.nvim_win_set_option(state.hover_win, "wrap", true) - vim.api.nvim_win_set_option(state.hover_win, "cursorline", false) - update_hover() + if not has_code_win() then + return + end + local code_buf = vim.api.nvim_win_get_buf(main.state.code_win) + local ft = vim.api.nvim_buf_get_option(code_buf, 'filetype') + vim.api.nvim_buf_set_option(state.hover_buf, 'syntax', ft) + vim.api.nvim_buf_set_option(state.hover_buf, 'bufhidden', 'delete') + vim.api.nvim_win_set_option(state.hover_win, 'wrap', true) + vim.api.nvim_win_set_option(state.hover_win, 'cursorline', false) + update_hover() end local function set_bg_hl() - local winhi = "Normal:" .. config.options.preview_bg_highlight - vim.api.nvim_win_set_option(state.preview_win, "winhighlight", winhi) - vim.api.nvim_win_set_option(state.hover_win, "winhighlight", winhi) + local winhi = 'Normal:' .. config.options.preview_bg_highlight + vim.api.nvim_win_set_option(state.preview_win, 'winhighlight', winhi) + vim.api.nvim_win_set_option(state.hover_win, 'winhighlight', winhi) end local function show_preview() - if state.preview_win == nil and state.preview_buf == nil then - state.preview_buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_attach(state.preview_buf, false, { - on_detach = function() - state.preview_buf = nil - state.preview_win = nil - end, - }) - local offsets = get_offset() - state.preview_win = vim.api.nvim_open_win(state.preview_buf, false, { - relative = "win", - width = 50, - height = get_height(), - bufpos = { 0, 0 }, - row = offsets[1], - col = offsets[2], - border = config.options.border, - }) - setup_preview_buf() - else - update_preview() - end + if state.preview_win == nil and state.preview_buf == nil then + state.preview_buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_attach(state.preview_buf, false, { + on_detach = function() + state.preview_buf = nil + state.preview_win = nil + end, + }) + local offsets = get_offset() + state.preview_win = vim.api.nvim_open_win(state.preview_buf, false, { + relative = 'win', + width = 50, + height = get_height(), + bufpos = { 0, 0 }, + row = offsets[1], + col = offsets[2], + border = config.options.border, + }) + setup_preview_buf() + else + update_preview() + end end local function show_hover() - if state.hover_win == nil and state.hover_buf == nil then - state.hover_buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_attach(state.hover_buf, false, { - on_detach = function() - state.hover_buf = nil - state.hover_win = nil - end, - }) - local offsets = get_offset() - local height = get_height() - state.hover_win = vim.api.nvim_open_win(state.hover_buf, false, { - relative = "win", - width = 50, - height = height, - bufpos = { 0, 0 }, - row = offsets[1] + height + 2, - col = offsets[2], - border = config.options.border, - }) - setup_hover_buf() - else - update_hover() - end + if state.hover_win == nil and state.hover_buf == nil then + state.hover_buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_attach(state.hover_buf, false, { + on_detach = function() + state.hover_buf = nil + state.hover_win = nil + end, + }) + local offsets = get_offset() + local height = get_height() + state.hover_win = vim.api.nvim_open_win(state.hover_buf, false, { + relative = 'win', + width = 50, + height = height, + bufpos = { 0, 0 }, + row = offsets[1] + height + 2, + col = offsets[2], + border = config.options.border, + }) + setup_hover_buf() + else + update_hover() + end end function M.show() - if not is_current_win_outline() or #vim.api.nvim_list_wins() < 2 then - return - end + if not is_current_win_outline() or #vim.api.nvim_list_wins() < 2 then + return + end - show_preview() - show_hover() - set_bg_hl() + show_preview() + show_hover() + set_bg_hl() end function M.close() - if has_code_win() then - if state.preview_win ~= nil and vim.api.nvim_win_is_valid(state.preview_win) then - vim.api.nvim_win_close(state.preview_win, true) - end - if state.hover_win ~= nil and vim.api.nvim_win_is_valid(state.hover_win) then - vim.api.nvim_win_close(state.hover_win, true) - end - end + if has_code_win() then + if state.preview_win ~= nil and vim.api.nvim_win_is_valid(state.preview_win) then + vim.api.nvim_win_close(state.preview_win, true) + end + if state.hover_win ~= nil and vim.api.nvim_win_is_valid(state.hover_win) then + vim.api.nvim_win_close(state.hover_win, true) + end + end end function M.toggle() - if state.preview_win ~= nil then - M.close() - else - M.show() - end + if state.preview_win ~= nil then + M.close() + else + M.show() + end end return M diff --git a/lua/symbols-outline/providers/coc.lua b/lua/symbols-outline/providers/coc.lua index fcd1d49..7bc3abc 100644 --- a/lua/symbols-outline/providers/coc.lua +++ b/lua/symbols-outline/providers/coc.lua @@ -1,31 +1,31 @@ local M = {} function M.should_use_provider(_) - local not_coc_installed = vim.fn.exists("*CocActionAsync") == 0 - local not_coc_service_initialized = vim.g.coc_service_initialized == 0 + local not_coc_installed = vim.fn.exists '*CocActionAsync' == 0 + local not_coc_service_initialized = vim.g.coc_service_initialized == 0 - if not_coc_installed or not_coc_service_initialized then - return - end + if not_coc_installed or not_coc_service_initialized then + return + end - local coc_attached = vim.fn.call("CocAction", { "ensureDocument" }) - local has_symbols = vim.fn.call("CocHasProvider", { "documentSymbol" }) + local coc_attached = vim.fn.call('CocAction', { 'ensureDocument' }) + local has_symbols = vim.fn.call('CocHasProvider', { 'documentSymbol' }) - return coc_attached and has_symbols + return coc_attached and has_symbols end function M.hover_info(_, _, on_info) - on_info(nil, { contents = { kind = "markdown", contents = { "No extra information availaible!" } } }) + on_info(nil, { contents = { kind = 'markdown', contents = { 'No extra information availaible!' } } }) end ---@param on_symbols function function M.request_symbols(on_symbols) - vim.fn.call("CocActionAsync", { - "documentSymbols", - function(_, symbols) - on_symbols({ [1000000] = { result = symbols } }) - end, - }) + vim.fn.call('CocActionAsync', { + 'documentSymbols', + function(_, symbols) + on_symbols { [1000000] = { result = symbols } } + end, + }) end return M diff --git a/lua/symbols-outline/providers/init.lua b/lua/symbols-outline/providers/init.lua index da3622f..8f11389 100644 --- a/lua/symbols-outline/providers/init.lua +++ b/lua/symbols-outline/providers/init.lua @@ -1,35 +1,35 @@ local M = {} local providers = { - "symbols-outline/providers/nvim-lsp", - "symbols-outline/providers/coc", - "symbols-outline/providers/markdown", + 'symbols-outline/providers/nvim-lsp', + 'symbols-outline/providers/coc', + 'symbols-outline/providers/markdown', } _G._symbols_outline_current_provider = nil function M.has_provider() - local ret = false - for _, value in ipairs(providers) do - local provider = require(value) - if provider.should_use_provider(0) then - ret = true - break - end - end - return ret + local ret = false + for _, value in ipairs(providers) do + local provider = require(value) + if provider.should_use_provider(0) then + ret = true + break + end + end + return ret end ---@param on_symbols function function M.request_symbols(on_symbols) - for _, value in ipairs(providers) do - local provider = require(value) - if provider.should_use_provider(0) then - _G._symbols_outline_current_provider = provider - provider.request_symbols(on_symbols) - break - end - end + for _, value in ipairs(providers) do + local provider = require(value) + if provider.should_use_provider(0) then + _G._symbols_outline_current_provider = provider + provider.request_symbols(on_symbols) + break + end + end end return M diff --git a/lua/symbols-outline/providers/markdown.lua b/lua/symbols-outline/providers/markdown.lua index 62e71b1..f93fe63 100644 --- a/lua/symbols-outline/providers/markdown.lua +++ b/lua/symbols-outline/providers/markdown.lua @@ -1,19 +1,19 @@ -local md_parser = require("symbols-outline.markdown") +local md_parser = require 'symbols-outline.markdown' local M = {} -- probably change this function M.should_use_provider(bufnr) - return string.match(vim.api.nvim_buf_get_option(bufnr, "ft"), "markdown") + return string.match(vim.api.nvim_buf_get_option(bufnr, 'ft'), 'markdown') end function M.hover_info(_, _, on_info) - on_info(nil, { contents = { kind = "markdown", contents = { "No extra information availaible!" } } }) + on_info(nil, { contents = { kind = 'markdown', contents = { 'No extra information availaible!' } } }) end ---@param on_symbols function function M.request_symbols(on_symbols) - on_symbols(md_parser.handle_markdown()) + on_symbols(md_parser.handle_markdown()) end return M diff --git a/lua/symbols-outline/providers/nvim-lsp.lua b/lua/symbols-outline/providers/nvim-lsp.lua index ccb5d17..447a8e4 100644 --- a/lua/symbols-outline/providers/nvim-lsp.lua +++ b/lua/symbols-outline/providers/nvim-lsp.lua @@ -1,57 +1,57 @@ -local config = require("symbols-outline.config") +local config = require 'symbols-outline.config' local M = {} local function getParams() - return { textDocument = vim.lsp.util.make_text_document_params() } + return { textDocument = vim.lsp.util.make_text_document_params() } end function M.hover_info(bufnr, params, on_info) - local clients = vim.lsp.buf_get_clients(bufnr) - local used_client + local clients = vim.lsp.buf_get_clients(bufnr) + local used_client - for id, client in pairs(clients) do - if config.is_client_blacklisted(id) then - goto continue - else - if client.server_capabilities.hoverProvider then - used_client = client - break - end - end - ::continue:: - end + for id, client in pairs(clients) do + if config.is_client_blacklisted(id) then + goto continue + else + if client.server_capabilities.hoverProvider then + used_client = client + break + end + end + ::continue:: + end - if not used_client then - on_info(nil, { contents = { kind = "markdown", content = { "No extra information availaible!" } } }) - end + if not used_client then + on_info(nil, { contents = { kind = 'markdown', content = { 'No extra information availaible!' } } }) + end - used_client.request("textDocument/hover", params, on_info, bufnr) + used_client.request('textDocument/hover', params, on_info, bufnr) end -- probably change this function M.should_use_provider(bufnr) - local clients = vim.lsp.buf_get_clients(bufnr) - local ret = false + local clients = vim.lsp.buf_get_clients(bufnr) + local ret = false - for id, client in pairs(clients) do - if config.is_client_blacklisted(id) then - goto continue - else - if client.server_capabilities.documentSymbolProvider then - ret = true - break - end - end - ::continue:: - end + for id, client in pairs(clients) do + if config.is_client_blacklisted(id) then + goto continue + else + if client.server_capabilities.documentSymbolProvider then + ret = true + break + end + end + ::continue:: + end - return ret + return ret end ---@param on_symbols function function M.request_symbols(on_symbols) - vim.lsp.buf_request_all(0, "textDocument/documentSymbol", getParams(), on_symbols) + vim.lsp.buf_request_all(0, 'textDocument/documentSymbol', getParams(), on_symbols) end return M diff --git a/lua/symbols-outline/rename.lua b/lua/symbols-outline/rename.lua index 655a94a..25a06f0 100644 --- a/lua/symbols-outline/rename.lua +++ b/lua/symbols-outline/rename.lua @@ -1,38 +1,39 @@ local vim = vim -local main = require('symbols-outline') +local main = require 'symbols-outline' local buf_request = require('symbols-outline.utils.lsp_utils').request local M = {} local function get_rename_params(node, winnr) - local bufnr = vim.api.nvim_win_get_buf(winnr) - local fn = "file://" .. vim.api.nvim_buf_get_name(bufnr) + local bufnr = vim.api.nvim_win_get_buf(winnr) + local fn = 'file://' .. vim.api.nvim_buf_get_name(bufnr) - return { - textDocument = {uri = fn}, - position = {line = node.line, character = node.character}, - bufnr = bufnr - } + return { + textDocument = { uri = fn }, + position = { line = node.line, character = node.character }, + bufnr = bufnr, + } end function M.rename() - local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] - local node = main.state.flattened_outline_items[current_line] + local current_line = vim.api.nvim_win_get_cursor(main.state.outline_win)[1] + local node = main.state.flattened_outline_items[current_line] - local params = get_rename_params(node, main.state.code_win) + local params = get_rename_params(node, main.state.code_win) - local new_name = vim.fn.input("New Name: ", node.name) - if not new_name or new_name == "" or new_name == node.name then return end + local new_name = vim.fn.input('New Name: ', node.name) + if not new_name or new_name == '' or new_name == node.name then + return + end - params.newName = new_name + params.newName = new_name - buf_request(params.bufnr, "textDocument/rename", params, - function(_, result) - if result ~= nil then - vim.lsp.util.apply_workspace_edit(result) - end - end) + buf_request(params.bufnr, 'textDocument/rename', params, function(_, result) + if result ~= nil then + vim.lsp.util.apply_workspace_edit(result) + end + end) end return M diff --git a/lua/symbols-outline/symbols.lua b/lua/symbols-outline/symbols.lua index 4345bed..33d17df 100644 --- a/lua/symbols-outline/symbols.lua +++ b/lua/symbols-outline/symbols.lua @@ -1,24 +1,48 @@ -local config = require('symbols-outline.config') +local config = require 'symbols-outline.config' local M = {} M.kinds = { - "File", "Module", "Namespace", "Package", "Class", "Method", "Property", - "Field", "Constructor", "Enum", "Interface", "Function", "Variable", - "Constant", "String", "Number", "Boolean", "Array", "Object", "Key", "Null", - "EnumMember", "Struct", "Event", "Operator", "TypeParameter" + 'File', + 'Module', + 'Namespace', + 'Package', + 'Class', + 'Method', + 'Property', + 'Field', + 'Constructor', + 'Enum', + 'Interface', + 'Function', + 'Variable', + 'Constant', + 'String', + 'Number', + 'Boolean', + 'Array', + 'Object', + 'Key', + 'Null', + 'EnumMember', + 'Struct', + 'Event', + 'Operator', + 'TypeParameter', } function M.icon_from_kind(kind) - local symbols = config.options.symbols + local symbols = config.options.symbols - if type(kind) == 'string' then - return symbols[kind].icon - end + if type(kind) == 'string' then + return symbols[kind].icon + end - -- If the kind is higher than the available ones then default to 'Object' - if kind > #M.kinds then kind = 19 end - return symbols[M.kinds[kind]].icon + -- If the kind is higher than the available ones then default to 'Object' + if kind > #M.kinds then + kind = 19 + end + return symbols[M.kinds[kind]].icon end return M diff --git a/lua/symbols-outline/ui.lua b/lua/symbols-outline/ui.lua index f8bdc4b..f46e932 100644 --- a/lua/symbols-outline/ui.lua +++ b/lua/symbols-outline/ui.lua @@ -1,57 +1,54 @@ local vim = vim -local config = require('symbols-outline.config') +local config = require 'symbols-outline.config' local symbol_kinds = require('symbols-outline.symbols').kinds local M = {} M.markers = { - bottom = "└", - middle = "├", - vertical = "│", - horizontal = "─" + bottom = '└', + middle = '├', + vertical = '│', + horizontal = '─', } -M.hovered_hl_ns = vim.api.nvim_create_namespace("hovered_item") +M.hovered_hl_ns = vim.api.nvim_create_namespace 'hovered_item' function M.clear_hover_highlight(bufnr) - vim.api.nvim_buf_clear_namespace(bufnr, M.hovered_hl_ns, 0, -1) + vim.api.nvim_buf_clear_namespace(bufnr, M.hovered_hl_ns, 0, -1) end function M.add_hover_highlight(bufnr, line, col_start) - vim.api.nvim_buf_add_highlight(bufnr, M.hovered_hl_ns, "FocusedSymbol", - line, col_start, -1) + vim.api.nvim_buf_add_highlight(bufnr, M.hovered_hl_ns, 'FocusedSymbol', line, col_start, -1) end local function highlight_text(name, text, hl_group) - vim.cmd(string.format("syn match %s /%s/", name, text)) - vim.cmd(string.format("hi def link %s %s", name, hl_group)) + vim.cmd(string.format('syn match %s /%s/', name, text)) + vim.cmd(string.format('hi def link %s %s', name, hl_group)) end function M.setup_highlights() - -- Setup the FocusedSymbol highlight group if it hasn't been done already by - -- a theme or manually set - if vim.fn.hlexists('FocusedSymbol') == 0 then - vim.cmd 'hi FocusedSymbol term=italic,bold cterm=italic ctermbg=yellow ctermfg=darkblue gui=bold,italic guibg=yellow guifg=darkblue' - end + -- Setup the FocusedSymbol highlight group if it hasn't been done already by + -- a theme or manually set + if vim.fn.hlexists 'FocusedSymbol' == 0 then + vim.cmd 'hi FocusedSymbol term=italic,bold cterm=italic ctermbg=yellow ctermfg=darkblue gui=bold,italic guibg=yellow guifg=darkblue' + end - -- Some colorschemes do some funky things with the comment highlight, most - -- notably making them italic, which messes up the outline connector. Fix - -- this by copying the foreground color from the comment hl into a new - -- highlight. - local comment_fg_gui = vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID('Comment')), 'fg', 'gui') + -- Some colorschemes do some funky things with the comment highlight, most + -- notably making them italic, which messes up the outline connector. Fix + -- this by copying the foreground color from the comment hl into a new + -- highlight. + local comment_fg_gui = vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID 'Comment'), 'fg', 'gui') - if vim.fn.hlexists('SymbolsOutlineConnector') == 0 then - vim.cmd(string.format('hi SymbolsOutlineConnector guifg=%s', comment_fg_gui)) - end + if vim.fn.hlexists 'SymbolsOutlineConnector' == 0 then + vim.cmd(string.format('hi SymbolsOutlineConnector guifg=%s', comment_fg_gui)) + end - local symbols = config.options.symbols + local symbols = config.options.symbols - -- markers - highlight_text("marker_middle", M.markers.middle, "SymbolsOutlineConnector") - highlight_text("marker_vertical", M.markers.vertical, - "SymbolsOutlineConnector") - highlight_text("markers_horizontal", M.markers.horizontal, - "SymbolsOutlineConnector") - highlight_text("markers_bottom", M.markers.bottom, "SymbolsOutlineConnector") + -- markers + highlight_text('marker_middle', M.markers.middle, 'SymbolsOutlineConnector') + highlight_text('marker_vertical', M.markers.vertical, 'SymbolsOutlineConnector') + highlight_text('markers_horizontal', M.markers.horizontal, 'SymbolsOutlineConnector') + highlight_text('markers_bottom', M.markers.bottom, 'SymbolsOutlineConnector') end return M diff --git a/lua/symbols-outline/utils/init.lua b/lua/symbols-outline/utils/init.lua index 7917979..0033c8f 100644 --- a/lua/symbols-outline/utils/init.lua +++ b/lua/symbols-outline/utils/init.lua @@ -4,28 +4,33 @@ local M = {} ---@param keys table|string ---@param action string function M.nmap(bufnr, keys, action) - if type(keys) == 'string' then keys = {keys} end + if type(keys) == 'string' then + keys = { keys } + end - for _, value in ipairs(keys) do - vim.api.nvim_buf_set_keymap(bufnr, "n", value, action, - {silent = true, noremap = true}) - end + for _, value in ipairs(keys) do + vim.api.nvim_buf_set_keymap(bufnr, 'n', value, action, { silent = true, noremap = true }) + end end --- @param f function --- @param delay number --- @return function function M.debounce(f, delay) - local timer = vim.loop.new_timer() + local timer = vim.loop.new_timer() - return function (...) - local args = { ... } + return function(...) + local args = { ... } - timer:start(delay, 0, vim.schedule_wrap(function () - timer:stop() - f(unpack(args)) - end)) - end + timer:start( + delay, + 0, + vim.schedule_wrap(function() + timer:stop() + f(unpack(args)) + end) + ) + end end return M diff --git a/lua/symbols-outline/utils/lsp_utils.lua b/lua/symbols-outline/utils/lsp_utils.lua index 83c410f..0fc15ba 100644 --- a/lua/symbols-outline/utils/lsp_utils.lua +++ b/lua/symbols-outline/utils/lsp_utils.lua @@ -7,7 +7,7 @@ local M = {} local function mk_handler(fn) return function(...) local config_or_client_id = select(4, ...) - local is_new = type(config_or_client_id) ~= "number" + local is_new = type(config_or_client_id) ~= 'number' if is_new then fn(...) else @@ -28,12 +28,12 @@ function M.request(bufnr, method, params, handler) end function M.is_buf_attached_to_lsp(bufnr) - local clients = vim.lsp.buf_get_clients(bufnr or 0) - return clients ~= nil and #clients > 0 + local clients = vim.lsp.buf_get_clients(bufnr or 0) + return clients ~= nil and #clients > 0 end function M.is_buf_markdown(bufnr) - return vim.api.nvim_buf_get_option(bufnr, 'ft') == 'markdown' + return vim.api.nvim_buf_get_option(bufnr, 'ft') == 'markdown' end return M diff --git a/lua/symbols-outline/view.lua b/lua/symbols-outline/view.lua index 5dd9dde..4d3f4a0 100644 --- a/lua/symbols-outline/view.lua +++ b/lua/symbols-outline/view.lua @@ -1,4 +1,4 @@ -local config = require('symbols-outline.config') +local config = require 'symbols-outline.config' local M = {} @@ -6,38 +6,38 @@ local M = {} ---@return string bufnr ---@return string bufnr function M.setup_view() - -- create a scratch unlisted buffer - local bufnr = vim.api.nvim_create_buf(false, true) + -- create a scratch unlisted buffer + local bufnr = vim.api.nvim_create_buf(false, true) - -- delete buffer when window is closed / buffer is hidden - vim.api.nvim_buf_set_option(bufnr, "bufhidden", "delete") - -- create a split - vim.cmd(config.get_split_command()) - -- resize to a % of the current window size - vim.cmd("vertical resize " .. config.get_window_width()) + -- delete buffer when window is closed / buffer is hidden + vim.api.nvim_buf_set_option(bufnr, 'bufhidden', 'delete') + -- create a split + vim.cmd(config.get_split_command()) + -- resize to a % of the current window size + vim.cmd('vertical resize ' .. config.get_window_width()) - -- get current (outline) window and attach our buffer to it - local winnr = vim.api.nvim_get_current_win() - vim.api.nvim_win_set_buf(winnr, bufnr) + -- get current (outline) window and attach our buffer to it + local winnr = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_buf(winnr, bufnr) - -- window stuff - vim.api.nvim_win_set_option(winnr, "number", false) - vim.api.nvim_win_set_option(winnr, "relativenumber", false) - vim.api.nvim_win_set_option(winnr, "winfixwidth", true) - -- buffer stuff - vim.api.nvim_buf_set_name(bufnr, "OUTLINE") - vim.api.nvim_buf_set_option(bufnr, "filetype", "Outline") - vim.api.nvim_buf_set_option(bufnr, "modifiable", false) + -- window stuff + vim.api.nvim_win_set_option(winnr, 'number', false) + vim.api.nvim_win_set_option(winnr, 'relativenumber', false) + vim.api.nvim_win_set_option(winnr, 'winfixwidth', true) + -- buffer stuff + vim.api.nvim_buf_set_name(bufnr, 'OUTLINE') + vim.api.nvim_buf_set_option(bufnr, 'filetype', 'Outline') + vim.api.nvim_buf_set_option(bufnr, 'modifiable', false) - if config.options.show_numbers or config.options.show_relative_numbers then - vim.api.nvim_win_set_option(winnr, "nu", true) - end + if config.options.show_numbers or config.options.show_relative_numbers then + vim.api.nvim_win_set_option(winnr, 'nu', true) + end - if config.options.show_relative_numbers then - vim.api.nvim_win_set_option(winnr, "rnu", true) - end + if config.options.show_relative_numbers then + vim.api.nvim_win_set_option(winnr, 'rnu', true) + end - return bufnr, winnr + return bufnr, winnr end return M diff --git a/lua/symbols-outline/writer.lua b/lua/symbols-outline/writer.lua index 5b959e9..c9afd3a 100644 --- a/lua/symbols-outline/writer.lua +++ b/lua/symbols-outline/writer.lua @@ -1,62 +1,68 @@ local vim = vim -local parser = require('symbols-outline.parser') -local config = require('symbols-outline.config') +local parser = require 'symbols-outline.parser' +local config = require 'symbols-outline.config' local M = {} local function is_buffer_outline(bufnr) - local isValid = vim.api.nvim_buf_is_valid(bufnr) - local name = vim.api.nvim_buf_get_name(bufnr) - local ft = vim.api.nvim_buf_get_option(bufnr, "filetype") - return string.match(name, "OUTLINE") ~= nil and ft == "Outline" and isValid + local isValid = vim.api.nvim_buf_is_valid(bufnr) + local name = vim.api.nvim_buf_get_name(bufnr) + local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype') + return string.match(name, 'OUTLINE') ~= nil and ft == 'Outline' and isValid end -local hlns = vim.api.nvim_create_namespace("symbols-outline-icon-highlight") +local hlns = vim.api.nvim_create_namespace 'symbols-outline-icon-highlight' function M.write_outline(bufnr, lines) - if not is_buffer_outline(bufnr) then return end - vim.api.nvim_buf_set_option(bufnr, "modifiable", true) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - vim.api.nvim_buf_set_option(bufnr, "modifiable", false) + if not is_buffer_outline(bufnr) then + return + end + vim.api.nvim_buf_set_option(bufnr, 'modifiable', true) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + vim.api.nvim_buf_set_option(bufnr, 'modifiable', false) end function M.add_highlights(bufnr, hl_info) - for line, line_hl in ipairs(hl_info) do - hl_start, hl_end, hl_type = unpack(line_hl) - vim.api.nvim_buf_add_highlight(bufnr, hlns, hl_type, line - 1, hl_start, hl_end) - end + for line, line_hl in ipairs(hl_info) do + hl_start, hl_end, hl_type = unpack(line_hl) + vim.api.nvim_buf_add_highlight(bufnr, hlns, hl_type, line - 1, hl_start, hl_end) + end end -local ns = vim.api.nvim_create_namespace("symbols-outline-virt-text") +local ns = vim.api.nvim_create_namespace 'symbols-outline-virt-text' function M.write_details(bufnr, lines) - if not is_buffer_outline(bufnr) then return end - if not config.options.show_symbol_details then return end + if not is_buffer_outline(bufnr) then + return + end + if not config.options.show_symbol_details then + return + end - for index, value in ipairs(lines) do - vim.api.nvim_buf_set_extmark(bufnr, ns, index - 1, -1, { - virt_text = {{value, "Comment"}}, - virt_text_pos = "eol", - hl_mode = "combine" - }) - end + for index, value in ipairs(lines) do + vim.api.nvim_buf_set_extmark(bufnr, ns, index - 1, -1, { + virt_text = { { value, 'Comment' } }, + virt_text_pos = 'eol', + hl_mode = 'combine', + }) + end end local function clear_virt_text(bufnr) - vim.api.nvim_buf_clear_namespace(bufnr, -1, 0, -1) + vim.api.nvim_buf_clear_namespace(bufnr, -1, 0, -1) end -- runs the whole writing routine where the text is cleared, new data is parsed -- and then written function M.parse_and_write(bufnr, flattened_outline_items) - local lines, hl_info = parser.get_lines(flattened_outline_items) - M.write_outline(bufnr, lines) + local lines, hl_info = parser.get_lines(flattened_outline_items) + M.write_outline(bufnr, lines) - clear_virt_text(bufnr) - local details = parser.get_details(flattened_outline_items) - M.add_highlights(bufnr, hl_info) - M.write_details(bufnr, details) + clear_virt_text(bufnr) + local details = parser.get_details(flattened_outline_items) + M.add_highlights(bufnr, hl_info) + M.write_details(bufnr, details) end return M diff --git a/stylua.toml b/stylua.toml new file mode 100644 index 0000000..237e120 --- /dev/null +++ b/stylua.toml @@ -0,0 +1,6 @@ +column_width = 120 +line_endings = 'Unix' +indent_type = 'Spaces' +indent_width = 2 +quote_style = 'AutoPreferSingle' +call_parentheses = 'None'