-
-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathmarkdown.lua
More file actions
145 lines (127 loc) · 4.03 KB
/
Copy pathmarkdown.lua
File metadata and controls
145 lines (127 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
-- NOTE
-- 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.
--
-- 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). That is, if the user has an applicable markdown LSP.
--
-- If they don't this provider will always work as usual.
local M = {
name = 'markdown',
}
local utils = require('outline.utils')
---@param bufnr integer
---@param config table?
---@return boolean ft_is_markdown
function M.supports_buffer(bufnr, config)
local ft = utils.buf_get_option(bufnr, 'ft')
if config and config.filetypes then
for _, ft_check in ipairs(config.filetypes) do
if ft_check == ft then
return true
end
end
end
return ft == 'markdown'
end
-- Parses markdown files and returns a table of SymbolInformation[] which is
-- used by the plugin to show the outline.
---@return outline.ProviderSymbol[]
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
-- Skip YAML frontmatter
local start_line = 1
if lines[1] and string.match(lines[1], '^---%s*$') then
for i = 2, #lines do
if string.match(lines[i], '^---%s*$') or string.match(lines[i], '^%.%.%.%s*$') then
start_line = i + 1
break
end
end
end
for line, value in ipairs(lines) do
if line < start_line then
goto nextline
end
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
-- -1 for 0-index, -1 to not include current line
-- TODO: This fix can be removed when we let highlight_hovered_item
-- account for current column position in addition to the line
level_symbols[i].selectionRange['end'].line = line - 2
level_symbols[i].range['end'].line = line - 2
level_symbols[i] = nil
end
end
max_level = depth
local entry = {
kind = 15,
name = title,
selectionRange = {
start = { character = 0, line = line - 1 },
['end'] = { character = 0, line = line - 1 },
},
range = {
start = { character = 0, line = line - 1 },
['end'] = { character = 0, 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 fun(symbols?:outline.ProviderSymbol[], opts?:table)
---@param opts table
function M.request_symbols(on_symbols, opts)
on_symbols(M.handle_markdown(), opts)
end
return M