1
- local Buffer = require (' render-markdown.lib.buffer' )
2
1
local Compat = require (' render-markdown.lib.compat' )
3
2
local Context = require (' render-markdown.request.context' )
3
+ local Decorator = require (' render-markdown.lib.decorator' )
4
4
local Env = require (' render-markdown.lib.env' )
5
5
local Extmark = require (' render-markdown.lib.extmark' )
6
6
local Iter = require (' render-markdown.lib.iter' )
7
+ local Range = require (' render-markdown.lib.range' )
7
8
local handlers = require (' render-markdown.core.handlers' )
8
9
local log = require (' render-markdown.core.log' )
9
10
local state = require (' render-markdown.state' )
@@ -18,26 +19,26 @@ local M = {}
18
19
M .ns = vim .api .nvim_create_namespace (' render-markdown.nvim' )
19
20
20
21
--- @private
21
- --- @type table<integer , render.md.Buffer >
22
+ --- @type table<integer , render.md.Decorator >
22
23
M .cache = {}
23
24
24
25
--- called from state on setup
25
26
--- @param config render.md.ui.Config
26
27
function M .setup (config )
27
28
M .config = config
28
29
-- 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 )
31
32
end
32
33
M .cache = {}
33
34
end
34
35
35
36
--- @param buf integer
36
- --- @return render.md.Buffer
37
+ --- @return render.md.Decorator
37
38
function M .get (buf )
38
39
local result = M .cache [buf ]
39
40
if not result then
40
- result = Buffer .new (buf )
41
+ result = Decorator .new ()
41
42
M .cache [buf ] = result
42
43
end
43
44
return result
@@ -50,114 +51,148 @@ end
50
51
--- @param change boolean
51
52
function M .update (buf , win , event , change )
52
53
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 ()
68
55
end
69
56
70
57
--- @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
+
71
75
--- @param buf integer
72
76
--- @param win integer
73
77
--- @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
76
91
return
77
92
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
78
104
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
89
111
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 )
91
123
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
94
126
Env .win .set (window , name , value [next_state ])
95
127
end
96
128
end
97
-
98
129
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 })
119
132
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 })
122
135
end
123
136
end
124
137
125
138
--- @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
141
159
end
142
160
143
161
--- @private
144
- --- @param buf integer
145
- --- @param win integer
146
- --- @param config render.md.main.Config
147
- --- @param mode string
148
162
--- @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 )
151
165
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' )
153
167
return {}
154
168
end
155
169
-- 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 )
157
171
-- make sure injections are processed
158
172
context .view :parse (parser )
159
173
local marks = handlers .run (context , parser )
160
174
return Iter .list .map (marks , Extmark .new )
161
175
end
162
176
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
+
163
198
return M
0 commit comments