Skip to content

Commit df64d5d

Browse files
chore(refactor): use class for main update logic
## Details Rather than calling `run_update` inside of `ui` module, we now create and run an instance of the new `Updater` class which is still fully contained inside the `ui` module. Gives us easy access to shared fields, rather then passing them between all the methods as needed. The only things staying at the top level of `ui` are the namespace and clear methods, as those are shared between all instances / needed outside the context of an instance of update. Other changes: - move `file_types` out of `state` module FINISH THIS!!!!!!!! - `render.md.buffer.Config` -> `render.md.partial.Config` - `render.md.buffer.UserConfig` -> `render.md.partial.UserConfig` - `render.md.main.Config` -> `render.md.buf.Config` - `render-markdown.lib.buffer` -> `render-markdown.lib.decorator` - `render-markdown.lib.decorator` no longer contains logic to check for an empty buffer, this has been moved to a simple method in `env.buf` - hidden range creation has been moved out of `config` module and into the new `ui` `Updater` class (only usage) - `config` module has been split up to create an instance of a new `resolved` module, which contains the computed / normalized values needed at runtime. This inner instance is made public and implements some of the methods previously stored inside of `config` - rename completion source methods `setup` -> `init` for consistency
1 parent ca5c29f commit df64d5d

File tree

21 files changed

+349
-312
lines changed

21 files changed

+349
-312
lines changed

doc/render-markdown.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*render-markdown.txt* For NVIM v0.11.1 Last change: 2025 May 22
1+
*render-markdown.txt* For NVIM v0.11.1 Last change: 2025 May 23
22

33
==============================================================================
44
Table of Contents *render-markdown-table-of-contents*

lua/render-markdown/config/overrides.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---@class (exact) render.md.overrides.Config
2-
---@field buflisted table<boolean, render.md.buffer.UserConfig>
3-
---@field buftype table<string, render.md.buffer.UserConfig>
4-
---@field filetype table<string, render.md.buffer.UserConfig>
2+
---@field buflisted table<boolean, render.md.partial.UserConfig>
3+
---@field buftype table<string, render.md.partial.UserConfig>
4+
---@field filetype table<string, render.md.partial.UserConfig>
55

66
---@class render.md.overrides.Cfg
77
local M = {}

lua/render-markdown/core/manager.lua

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ local state = require('render-markdown.state')
44
local ui = require('render-markdown.core.ui')
55

66
---@class render.md.manager.Config
7+
---@field file_types string[]
78
---@field ignore fun(buf: integer): boolean
89
---@field change_events string[]
910
---@field on render.md.on.Config
@@ -103,13 +104,13 @@ function M.attach(buf)
103104
M.config.on.attach({ buf = buf })
104105
require('render-markdown.core.ts').init()
105106
if M.config.completions.lsp.enabled then
106-
require('render-markdown.integ.lsp').setup()
107+
require('render-markdown.integ.lsp').init()
107108
elseif M.config.completions.blink.enabled then
108-
require('render-markdown.integ.blink').setup()
109+
require('render-markdown.integ.blink').init()
109110
elseif M.config.completions.coq.enabled then
110-
require('render-markdown.integ.coq').setup()
111+
require('render-markdown.integ.coq').init()
111112
else
112-
require('render-markdown.integ.cmp').setup()
113+
require('render-markdown.integ.cmp').init()
113114
end
114115

115116
local events = {
@@ -122,7 +123,7 @@ function M.attach(buf)
122123
}
123124
local change_events = { 'DiffUpdated', 'ModeChanged', 'TextChanged' }
124125
vim.list_extend(change_events, M.config.change_events)
125-
if config:render('i') then
126+
if config.resolved:render('i') then
126127
vim.list_extend(events, { 'CursorHoldI', 'CursorMovedI' })
127128
vim.list_extend(change_events, { 'TextChangedI' })
128129
end
@@ -171,15 +172,17 @@ function M.should_attach(buf)
171172
return false
172173
end
173174

174-
local file_type, file_types = Env.buf.get(buf, 'filetype'), state.file_types
175+
local file_type = Env.buf.get(buf, 'filetype')
176+
local file_types = M.config.file_types
175177
if not vim.tbl_contains(file_types, file_type) then
176178
local reason = file_type .. ' /∈ ' .. vim.inspect(file_types)
177179
log.buf('info', 'attach', buf, 'skip', 'file type', reason)
178180
return false
179181
end
180182

181183
local config = state.get(buf)
182-
local file_size, max_file_size = Env.file_size_mb(buf), config.max_file_size
184+
local file_size = Env.file_size_mb(buf)
185+
local max_file_size = config.max_file_size
183186
if file_size > max_file_size then
184187
local reason = ('%f > %f'):format(file_size, max_file_size)
185188
log.buf('info', 'attach', buf, 'skip', 'file size', reason)

lua/render-markdown/core/ui.lua

Lines changed: 117 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
local Buffer = require('render-markdown.lib.buffer')
21
local Compat = require('render-markdown.lib.compat')
32
local Context = require('render-markdown.request.context')
3+
local Decorator = require('render-markdown.lib.decorator')
44
local Env = require('render-markdown.lib.env')
55
local Extmark = require('render-markdown.lib.extmark')
66
local Iter = require('render-markdown.lib.iter')
7+
local Range = require('render-markdown.lib.range')
78
local handlers = require('render-markdown.core.handlers')
89
local log = require('render-markdown.core.log')
910
local state = require('render-markdown.state')
@@ -18,26 +19,26 @@ local M = {}
1819
M.ns = vim.api.nvim_create_namespace('render-markdown.nvim')
1920

2021
---@private
21-
---@type table<integer, render.md.Buffer>
22+
---@type table<integer, render.md.Decorator>
2223
M.cache = {}
2324

2425
---called from state on setup
2526
---@param config render.md.ui.Config
2627
function M.setup(config)
2728
M.config = config
2829
-- reset cache
29-
for buf, buffer in pairs(M.cache) do
30-
M.clear_buffer(buf, buffer)
30+
for buf, decorator in pairs(M.cache) do
31+
M.clear(buf, decorator)
3132
end
3233
M.cache = {}
3334
end
3435

3536
---@param buf integer
36-
---@return render.md.Buffer
37+
---@return render.md.Decorator
3738
function M.get(buf)
3839
local result = M.cache[buf]
3940
if not result then
40-
result = Buffer.new(buf)
41+
result = Decorator.new()
4142
M.cache[buf] = result
4243
end
4344
return result
@@ -50,114 +51,148 @@ end
5051
---@param change boolean
5152
function M.update(buf, win, event, change)
5253
log.buf('info', 'update', buf, event, ('change %s'):format(change))
53-
if not Env.valid(buf, win) then
54-
return
55-
end
56-
57-
local parse = M.parse(buf, win, change)
58-
local config = state.get(buf)
59-
local buffer = M.get(buf)
60-
if buffer:is_empty() then
61-
return
62-
end
63-
64-
local update = log.runtime('update', function()
65-
M.run_update(buf, win, change)
66-
end)
67-
buffer:run(parse, config.debounce, update)
54+
M.updater.new(buf, win, change):start()
6855
end
6956

7057
---@private
58+
---@param buf integer
59+
---@param decorator render.md.Decorator
60+
function M.clear(buf, decorator)
61+
vim.api.nvim_buf_clear_namespace(buf, M.ns, 0, -1)
62+
decorator:clear()
63+
end
64+
65+
---@class render.md.ui.Updater
66+
---@field private buf integer
67+
---@field private win integer
68+
---@field private change boolean
69+
---@field private decorator render.md.Decorator
70+
---@field private config render.md.buf.Config
71+
---@field private mode string
72+
local Updater = {}
73+
Updater.__index = Updater
74+
7175
---@param buf integer
7276
---@param win integer
7377
---@param change boolean
74-
function M.run_update(buf, win, change)
75-
if not Env.valid(buf, win) then
78+
---@return render.md.ui.Updater
79+
function Updater.new(buf, win, change)
80+
local self = setmetatable({}, Updater)
81+
self.buf = buf
82+
self.win = win
83+
self.change = change
84+
self.decorator = M.get(buf)
85+
self.config = state.get(buf)
86+
return self
87+
end
88+
89+
function Updater:start()
90+
if not Env.valid(self.buf, self.win) then
7691
return
7792
end
93+
if Env.buf.empty(self.buf) then
94+
return
95+
end
96+
self.decorator:schedule(
97+
self:should_parse(),
98+
self.config.debounce,
99+
log.runtime('update', function()
100+
self:run()
101+
end)
102+
)
103+
end
78104

79-
local parse = M.parse(buf, win, change)
80-
local config = state.get(buf)
81-
local buffer = M.get(buf)
82-
local mode = Env.mode.get()
83-
local row = Env.row.get(buf, win)
84-
85-
local render = config.enabled
86-
and config:render(mode)
87-
and not Env.win.get(win, 'diff')
88-
and Env.win.view(win).leftcol == 0
105+
---@private
106+
---@return boolean
107+
function Updater:should_parse()
108+
-- need to parse on changes or when we have not parsed the visible range yet
109+
return self.change or not Context.contains(self.buf, self.win)
110+
end
89111

90-
log.buf('info', 'render', buf, render)
112+
---@private
113+
function Updater:run()
114+
if not Env.valid(self.buf, self.win) then
115+
return
116+
end
117+
self.mode = Env.mode.get() -- mode is only available after this point
118+
local render = self.config.enabled
119+
and self.config.resolved:render(self.mode)
120+
and not Env.win.get(self.win, 'diff')
121+
and Env.win.view(self.win).leftcol == 0
122+
log.buf('info', 'render', self.buf, render)
91123
local next_state = render and 'rendered' or 'default'
92-
for _, window in ipairs(Env.buf.windows(buf)) do
93-
for name, value in pairs(config.win_options) do
124+
for _, window in ipairs(Env.buf.windows(self.buf)) do
125+
for name, value in pairs(self.config.win_options) do
94126
Env.win.set(window, name, value[next_state])
95127
end
96128
end
97-
98129
if render then
99-
local initial = buffer:initial()
100-
if initial or parse then
101-
M.clear_buffer(buf, buffer)
102-
local extmarks = M.parse_buffer(buf, win, config, mode)
103-
buffer:set_marks(extmarks)
104-
if initial then
105-
Compat.fix_lsp_window(buf, win, extmarks)
106-
M.config.on.initial({ buf = buf, win = win })
107-
end
108-
end
109-
local range = config:hidden(mode, row)
110-
local extmarks = buffer:get_marks()
111-
for _, extmark in ipairs(extmarks) do
112-
if extmark:get().conceal and extmark:overlaps(range) then
113-
extmark:hide(M.ns, buf)
114-
else
115-
extmark:show(M.ns, buf)
116-
end
117-
end
118-
M.config.on.render({ buf = buf, win = win })
130+
self:render()
131+
M.config.on.render({ buf = self.buf, win = self.win })
119132
else
120-
M.clear_buffer(buf, buffer)
121-
M.config.on.clear({ buf = buf, win = win })
133+
M.clear(self.buf, self.decorator)
134+
M.config.on.clear({ buf = self.buf, win = self.win })
122135
end
123136
end
124137

125138
---@private
126-
---@param buf integer
127-
---@param win integer
128-
---@param change boolean
129-
---@return boolean
130-
function M.parse(buf, win, change)
131-
-- need to parse when things change or we have not parsed the visible range yet
132-
return change or not Context.contains(buf, win)
133-
end
134-
135-
---@private
136-
---@param buf integer
137-
---@param buffer render.md.Buffer
138-
function M.clear_buffer(buf, buffer)
139-
vim.api.nvim_buf_clear_namespace(buf, M.ns, 0, -1)
140-
buffer:set_marks(nil)
139+
function Updater:render()
140+
local initial = self.decorator:initial()
141+
if initial or self:should_parse() then
142+
M.clear(self.buf, self.decorator)
143+
local extmarks = self:get_extmarks()
144+
self.decorator:set(extmarks)
145+
if initial then
146+
Compat.fix_lsp_window(self.buf, self.win, extmarks)
147+
M.config.on.initial({ buf = self.buf, win = self.win })
148+
end
149+
end
150+
local range = self:hidden()
151+
local extmarks = self.decorator:get()
152+
for _, extmark in ipairs(extmarks) do
153+
if extmark:get().conceal and extmark:overlaps(range) then
154+
extmark:hide(M.ns, self.buf)
155+
else
156+
extmark:show(M.ns, self.buf)
157+
end
158+
end
141159
end
142160

143161
---@private
144-
---@param buf integer
145-
---@param win integer
146-
---@param config render.md.main.Config
147-
---@param mode string
148162
---@return render.md.Extmark[]
149-
function M.parse_buffer(buf, win, config, mode)
150-
local has_parser, parser = pcall(vim.treesitter.get_parser, buf)
163+
function Updater:get_extmarks()
164+
local has_parser, parser = pcall(vim.treesitter.get_parser, self.buf)
151165
if not has_parser or not parser then
152-
log.buf('error', 'fail', buf, 'no treesitter parser found')
166+
log.buf('error', 'fail', self.buf, 'no treesitter parser found')
153167
return {}
154168
end
155169
-- reset buffer context
156-
local context = Context.start(buf, win, config, mode)
170+
local context = Context.new(self.buf, self.win, self.config, self.mode)
157171
-- make sure injections are processed
158172
context.view:parse(parser)
159173
local marks = handlers.run(context, parser)
160174
return Iter.list.map(marks, Extmark.new)
161175
end
162176

177+
---@private
178+
---@return render.md.Range?
179+
function Updater:hidden()
180+
-- anti-conceal is not enabled -> hide nothing
181+
-- row is not known -> buffer is not active -> hide nothing
182+
local config = self.config.anti_conceal
183+
local row = Env.row.get(self.buf, self.win)
184+
if not config.enabled or not row then
185+
return nil
186+
end
187+
if Env.mode.is(self.mode, { 'v', 'V', '\22' }) then
188+
local start = vim.fn.getpos('v')[2] - 1
189+
return Range.new(math.min(row, start), math.max(row, start))
190+
else
191+
return Range.new(row - config.above, row + config.below)
192+
end
193+
end
194+
195+
---@private
196+
M.updater = Updater
197+
163198
return M

lua/render-markdown/debug/marks.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ function M.show()
158158
local range = Range.new(row, row)
159159

160160
local marks = {} ---@type render.md.debug.Mark[]
161-
for _, extmark in ipairs(ui.get(buf):get_marks()) do
161+
for _, extmark in ipairs(ui.get(buf):get()) do
162162
if extmark:overlaps(range) then
163163
marks[#marks + 1] = Mark.new(extmark:get())
164164
end

lua/render-markdown/health.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local state = require('render-markdown.state')
55
local M = {}
66

77
---@private
8-
M.version = '8.4.5'
8+
M.version = '8.4.6'
99

1010
function M.check()
1111
M.start('version')

lua/render-markdown/init.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---@class render.md.Init: render.md.Api
22
local M = {}
33

4-
---@class (exact) render.md.Config: render.md.buffer.Config
4+
---@class (exact) render.md.Config: render.md.partial.Config
55
---@field preset render.md.config.Preset
66
---@field log_level render.md.log.Level
77
---@field log_runtime boolean
@@ -15,7 +15,7 @@ local M = {}
1515
---@field overrides render.md.overrides.Config
1616
---@field custom_handlers table<string, render.md.Handler>
1717

18-
---@class (exact) render.md.buffer.Config: render.md.base.Config
18+
---@class (exact) render.md.partial.Config: render.md.base.Config
1919
---@field max_file_size number
2020
---@field debounce integer
2121
---@field anti_conceal render.md.anti.conceal.Config

0 commit comments

Comments
 (0)