@@ -1,91 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
-- Parses markdown files and returns a table of SymbolInformation[] which is
|
|
||||||
-- used by the plugin to show the outline.
|
|
||||||
-- We do this because markdown does not have a LSP.
|
|
||||||
-- 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
|
|
||||||
|
|
||||||
for line, value in ipairs(lines) do
|
|
||||||
if string.find(value, '^```') then
|
|
||||||
is_inside_code_block = not is_inside_code_block
|
|
||||||
end
|
|
||||||
if is_inside_code_block then
|
|
||||||
goto nextline
|
|
||||||
end
|
|
||||||
|
|
||||||
local next_value = lines[line+1]
|
|
||||||
local is_emtpy_line = #value:gsub("^%s*(.-)%s*$", "%1") == 0
|
|
||||||
|
|
||||||
local header, title = string.match(value, '^(#+)%s+(.+)$')
|
|
||||||
if not header and next_value and not is_emtpy_line then
|
|
||||||
if string.match(next_value, '^=+%s*$') then
|
|
||||||
header = '#'
|
|
||||||
title = value
|
|
||||||
elseif string.match(next_value, '^-+%s*$') then
|
|
||||||
header = '##'
|
|
||||||
title = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not header or not title then
|
|
||||||
goto nextline
|
|
||||||
end
|
|
||||||
-- TODO: This is not needed and it works?
|
|
||||||
-- if #header > 6 then
|
|
||||||
-- goto nextline
|
|
||||||
-- end
|
|
||||||
|
|
||||||
local depth = #header + 1
|
|
||||||
|
|
||||||
local parent
|
|
||||||
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
|
|
||||||
|
|
||||||
local 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
|
|
||||||
::nextline::
|
|
||||||
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 level_symbols[1].children
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -3,6 +3,11 @@ local M = {}
|
|||||||
local providers = {
|
local providers = {
|
||||||
'outline/providers/nvim-lsp',
|
'outline/providers/nvim-lsp',
|
||||||
'outline/providers/coc',
|
'outline/providers/coc',
|
||||||
|
-- NOTE: There is in fact a markdown LSP that can provide symbols. However
|
||||||
|
-- on buffer open the LSP may not be attached immediately. Before the LSP is
|
||||||
|
-- ready if the user opens the outline, our own markdown provider will be
|
||||||
|
-- used. After refreshing/reopening, the provider will then switch to the LSP
|
||||||
|
-- (if the user has a markdown LSP).
|
||||||
'outline/providers/markdown',
|
'outline/providers/markdown',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
local md_parser = require 'outline.markdown'
|
-- Our own markdown provider is used because legacy symbols-outline considered
|
||||||
|
-- the case where markdown does not have an LSP. However, it does, so as of now
|
||||||
|
-- this module is kept for use when user opens symbols outline before the
|
||||||
|
-- markdown LSP is ready. Please also see comment in providers/init.lua
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
-- probably change this
|
---@return boolean ft_is_markdown
|
||||||
function M.should_use_provider(bufnr)
|
function M.should_use_provider(bufnr)
|
||||||
return string.match(vim.api.nvim_buf_get_option(bufnr, 'ft'), 'markdown')
|
return vim.api.nvim_buf_get_option(bufnr, 'ft') == 'markdown'
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.hover_info(_, _, on_info)
|
function M.hover_info(_, _, on_info)
|
||||||
@@ -16,10 +19,96 @@ function M.hover_info(_, _, on_info)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Parses markdown files and returns a table of SymbolInformation[] which is
|
||||||
|
-- used by the plugin to show the outline.
|
||||||
|
---@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
|
||||||
|
|
||||||
|
for line, value in ipairs(lines) do
|
||||||
|
if string.find(value, '^```') then
|
||||||
|
is_inside_code_block = not is_inside_code_block
|
||||||
|
end
|
||||||
|
if is_inside_code_block then
|
||||||
|
goto nextline
|
||||||
|
end
|
||||||
|
|
||||||
|
local next_value = lines[line+1]
|
||||||
|
local is_emtpy_line = #value:gsub("^%s*(.-)%s*$", "%1") == 0
|
||||||
|
|
||||||
|
local header, title = string.match(value, '^(#+)%s+(.+)$')
|
||||||
|
if not header and next_value and not is_emtpy_line then
|
||||||
|
if string.match(next_value, '^=+%s*$') then
|
||||||
|
header = '#'
|
||||||
|
title = value
|
||||||
|
elseif string.match(next_value, '^-+%s*$') then
|
||||||
|
header = '##'
|
||||||
|
title = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not header or not title then
|
||||||
|
goto nextline
|
||||||
|
end
|
||||||
|
-- TODO: This is not needed and it works?
|
||||||
|
-- if #header > 6 then
|
||||||
|
-- goto nextline
|
||||||
|
-- end
|
||||||
|
|
||||||
|
local depth = #header + 1
|
||||||
|
|
||||||
|
local parent
|
||||||
|
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
|
||||||
|
|
||||||
|
local entry = {
|
||||||
|
kind = 15,
|
||||||
|
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
|
||||||
|
::nextline::
|
||||||
|
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 level_symbols[1].children
|
||||||
|
end
|
||||||
|
|
||||||
---@param on_symbols function
|
---@param on_symbols function
|
||||||
---@param opts table
|
---@param opts table
|
||||||
function M.request_symbols(on_symbols, opts)
|
function M.request_symbols(on_symbols, opts)
|
||||||
on_symbols(md_parser.handle_markdown(), opts)
|
on_symbols(M.handle_markdown(), opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
Reference in New Issue
Block a user