@@ -6,6 +6,7 @@ local colors = require('render-markdown.colors')
6
6
7
7
--- @class render.md.data.Heading
8
8
--- @field atx boolean
9
+ --- @field marker render.md.Node
9
10
--- @field level integer
10
11
--- @field icon ? string
11
12
--- @field sign ? string
@@ -17,7 +18,6 @@ local colors = require('render-markdown.colors')
17
18
--- @field right_pad number
18
19
--- @field min_width integer
19
20
--- @field border boolean
20
- --- @field end_row integer
21
21
22
22
--- @class render.md.width.Heading
23
23
--- @field margin integer
@@ -37,15 +37,24 @@ function Render:setup()
37
37
return false
38
38
end
39
39
40
- local atx , level = nil , nil
41
- if self .node .type == ' setext_heading' then
42
- atx , level = false , self .node :child (' setext_h1_underline' ) ~= nil and 1 or 2
40
+ local atx = nil
41
+ local marker = nil
42
+ local level = nil
43
+ if self .node .type == ' atx_heading' then
44
+ atx = true
45
+ marker = assert (self .node :child_at (0 ), ' atx heading expected child marker' )
46
+ level = Str .width (marker .text )
47
+ elseif self .node .type == ' setext_heading' then
48
+ atx = false
49
+ marker = assert (self .node :child_at (1 ), ' ext heading expected child underline' )
50
+ level = marker .type == ' setext_h1_underline' and 1 or 2
43
51
else
44
- atx , level = true , Str . width ( self . node . text )
52
+ return false
45
53
end
46
54
47
55
self .data = {
48
56
atx = atx ,
57
+ marker = marker ,
49
58
level = level ,
50
59
icon = List .cycle (self .heading .icons , level ),
51
60
sign = List .cycle (self .heading .signs , level ),
@@ -57,21 +66,23 @@ function Render:setup()
57
66
right_pad = List .clamp (self .heading .right_pad , level ) or 0 ,
58
67
min_width = List .clamp (self .heading .min_width , level ) or 0 ,
59
68
border = List .clamp (self .heading .border , level ) or false ,
60
- end_row = self .node .end_row + (atx and 1 or 0 ),
61
69
}
62
70
63
71
return true
64
72
end
65
73
66
74
function Render :render ()
67
- local width = self :width (self :icon ())
68
75
if self .heading .sign then
69
76
self :sign (self .data .sign , self .data .foreground )
70
77
end
78
+ local width = self :width (self :icon ())
71
79
self :background (width )
72
- self :border (width )
73
80
self :left_pad (width )
74
- self :conceal_underline ()
81
+ if self .data .atx then
82
+ self :border (width )
83
+ else
84
+ self :conceal_underline ()
85
+ end
75
86
end
76
87
77
88
--- @private
@@ -84,58 +95,78 @@ function Render:icon()
84
95
if self .data .background ~= nil then
85
96
table.insert (highlight , self .data .background )
86
97
end
87
-
88
- if not self .data .atx then
98
+ if self .data .atx then
99
+ local marker = self .data .marker
100
+ -- Add 1 to account for space after last `#`
101
+ local width = self .context :width (marker ) + 1
102
+ if icon == nil or # highlight == 0 then
103
+ return width
104
+ end
105
+ if self .heading .position == ' right' then
106
+ self .marks :add_over (true , marker , {
107
+ conceal = ' ' ,
108
+ }, { 0 , 0 , 0 , 1 })
109
+ self .marks :add_over (' head_icon' , marker , {
110
+ priority = 1000 ,
111
+ virt_text = { { icon , highlight } },
112
+ virt_text_pos = ' eol' ,
113
+ })
114
+ return 1 + Str .width (icon )
115
+ else
116
+ local padding = width - Str .width (icon )
117
+ if self .heading .position == ' inline' or padding < 0 then
118
+ local added = self .marks :add_over (true , marker , {
119
+ virt_text = { { icon , highlight } },
120
+ virt_text_pos = ' inline' ,
121
+ conceal = ' ' ,
122
+ }, { 0 , 0 , 0 , 1 })
123
+ return added and Str .width (icon ) or width
124
+ else
125
+ self .marks :add_over (' head_icon' , marker , {
126
+ virt_text = { { Str .pad (padding ) .. icon , highlight } },
127
+ virt_text_pos = ' overlay' ,
128
+ })
129
+ return width
130
+ end
131
+ end
132
+ else
133
+ local node = self .node
89
134
if icon == nil or # highlight == 0 then
90
135
return 0
91
136
end
92
- local added = true
93
- for row = self .node .start_row , self .data .end_row - 1 do
94
- added = added
95
- and self .marks :add (' head_icon' , row , self .node .start_col , {
137
+ if self .heading .position == ' right' then
138
+ self .marks :add_over (' head_icon' , node , {
139
+ priority = 1000 ,
140
+ virt_text = { { icon , highlight } },
141
+ virt_text_pos = ' eol' ,
142
+ })
143
+ return 1 + Str .width (icon )
144
+ else
145
+ local added = true
146
+ for row = node .start_row , node .end_row - 1 do
147
+ local added_row = self .marks :add (' head_icon' , row , node .start_col , {
96
148
end_row = row ,
97
- end_col = self . node .end_col ,
98
- virt_text = { { row == self . node .start_row and icon or Str .pad (Str .width (icon )), highlight } },
149
+ end_col = node .end_col ,
150
+ virt_text = { { row == node .start_row and icon or Str .pad (Str .width (icon )), highlight } },
99
151
virt_text_pos = ' inline' ,
100
152
})
153
+ added = added and added_row
154
+ end
155
+ return added and Str .width (icon ) or 0
101
156
end
102
- return added and Str .width (icon ) or 0
103
- end
104
-
105
- -- For atx headings we add 1 to the available width to account for the space after the last `#`
106
- local width = self .context :width (self .node ) + 1
107
- if icon == nil or # highlight == 0 then
108
- return width
109
- end
110
-
111
- local padding = width - Str .width (icon )
112
- if self .heading .position == ' inline' or padding < 0 then
113
- local added = self .marks :add_over (' head_icon' , self .node , {
114
- virt_text = { { icon , highlight } },
115
- virt_text_pos = ' inline' ,
116
- conceal = ' ' ,
117
- })
118
- return added and Str .width (icon ) + 1 or width
119
- else
120
- self .marks :add_over (' head_icon' , self .node , {
121
- virt_text = { { Str .pad (padding ) .. icon , highlight } },
122
- virt_text_pos = ' overlay' ,
123
- })
124
- return width
125
157
end
126
158
end
127
159
128
160
--- @private
129
161
--- @param icon_width integer
130
162
--- @return render.md.width.Heading
131
163
function Render :width (icon_width )
132
- local text_width = nil
164
+ local width = icon_width
133
165
if self .data .atx then
134
- text_width = self .context :width (self .node :sibling (' inline' ))
166
+ width = width + self .context :width (self .node :child (' inline' ))
135
167
else
136
- text_width = vim .fn .max (Iter .list .map (self .node :lines (), Str .width ))
168
+ width = width + vim .fn .max (Iter .list .map (self .node :lines (), Str .width ))
137
169
end
138
- local width = icon_width + text_width
139
170
local left_padding = self .context :resolve_offset (self .data .left_pad , width )
140
171
local right_padding = self .context :resolve_offset (self .data .right_pad , width )
141
172
width = math.max (left_padding + width + right_padding , self .data .min_width )
@@ -159,7 +190,7 @@ function Render:background(width)
159
190
win_col = width .margin + width .content + self :indent (self .data .level )
160
191
table.insert (padding , self :padding_text (vim .o .columns * 2 ))
161
192
end
162
- for row = self .node .start_row , self .data .end_row - 1 do
193
+ for row = self .node .start_row , self .node .end_row - 1 do
163
194
self .marks :add (' head_background' , row , 0 , {
164
195
end_row = row + 1 ,
165
196
hl_group = highlight ,
179
210
--- @private
180
211
--- @param width render.md.width.Heading
181
212
function Render :border (width )
182
- -- Only atx headings support borders
183
- if not self .data .border or not self .data .atx then
213
+ if not self .data .border then
184
214
return
185
215
end
186
216
@@ -226,13 +256,13 @@ function Render:border(width)
226
256
227
257
local line_below = line (self .heading .below )
228
258
if not virtual and self :empty_line (' below' ) then
229
- self .marks :add (' head_border' , self .node .end_row + 1 , 0 , {
259
+ self .marks :add (' head_border' , self .node .end_row , 0 , {
230
260
virt_text = line_below ,
231
261
virt_text_pos = ' overlay' ,
232
262
})
233
- self .context .last_heading = self .node .end_row + 1
263
+ self .context .last_heading = self .node .end_row
234
264
else
235
- self .marks :add (false , self .node .end_row , 0 , {
265
+ self .marks :add (false , self .node .start_row , 0 , {
236
266
virt_lines = { self :indent_virt_line (line_below , self .data .level ) },
237
267
})
238
268
end
@@ -256,27 +286,21 @@ function Render:left_pad(width)
256
286
if width .padding > 0 then
257
287
table.insert (virt_text , self :padding_text (width .padding , self .data .background ))
258
288
end
259
- if # virt_text > 0 then
260
- for row = self .node .start_row , self .data .end_row - 1 do
261
- self .marks :add (false , row , 0 , {
262
- priority = 0 ,
263
- virt_text = virt_text ,
264
- virt_text_pos = ' inline' ,
265
- })
266
- end
289
+ if # virt_text == 0 then
290
+ return
291
+ end
292
+ for row = self .node .start_row , self .node .end_row - 1 do
293
+ self .marks :add (false , row , 0 , {
294
+ priority = 0 ,
295
+ virt_text = virt_text ,
296
+ virt_text_pos = ' inline' ,
297
+ })
267
298
end
268
299
end
269
300
270
301
--- @private
271
302
function Render :conceal_underline ()
272
- if self .data .atx then
273
- return
274
- end
275
- local node = self .node :child (string.format (' setext_h%d_underline' , self .data .level ))
276
- if node == nil then
277
- return
278
- end
279
- self .marks :add_over (true , node , {
303
+ self .marks :add_over (true , self .data .marker , {
280
304
conceal = ' ' ,
281
305
})
282
306
end
0 commit comments