@@ -6,6 +6,7 @@ local colors = require('render-markdown.colors')
66
77--- @class render.md.data.Heading
88--- @field atx boolean
9+ --- @field marker render.md.Node
910--- @field level integer
1011--- @field icon ? string
1112--- @field sign ? string
@@ -17,7 +18,6 @@ local colors = require('render-markdown.colors')
1718--- @field right_pad number
1819--- @field min_width integer
1920--- @field border boolean
20- --- @field end_row integer
2121
2222--- @class render.md.width.Heading
2323--- @field margin integer
@@ -37,15 +37,24 @@ function Render:setup()
3737 return false
3838 end
3939
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
4351 else
44- atx , level = true , Str . width ( self . node . text )
52+ return false
4553 end
4654
4755 self .data = {
4856 atx = atx ,
57+ marker = marker ,
4958 level = level ,
5059 icon = List .cycle (self .heading .icons , level ),
5160 sign = List .cycle (self .heading .signs , level ),
@@ -57,21 +66,23 @@ function Render:setup()
5766 right_pad = List .clamp (self .heading .right_pad , level ) or 0 ,
5867 min_width = List .clamp (self .heading .min_width , level ) or 0 ,
5968 border = List .clamp (self .heading .border , level ) or false ,
60- end_row = self .node .end_row + (atx and 1 or 0 ),
6169 }
6270
6371 return true
6472end
6573
6674function Render :render ()
67- local width = self :width (self :icon ())
6875 if self .heading .sign then
6976 self :sign (self .data .sign , self .data .foreground )
7077 end
78+ local width = self :width (self :icon ())
7179 self :background (width )
72- self :border (width )
7380 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
7586end
7687
7788--- @private
@@ -84,58 +95,78 @@ function Render:icon()
8495 if self .data .background ~= nil then
8596 table.insert (highlight , self .data .background )
8697 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
89134 if icon == nil or # highlight == 0 then
90135 return 0
91136 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 , {
96148 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 } },
99151 virt_text_pos = ' inline' ,
100152 })
153+ added = added and added_row
154+ end
155+ return added and Str .width (icon ) or 0
101156 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
125157 end
126158end
127159
128160--- @private
129161--- @param icon_width integer
130162--- @return render.md.width.Heading
131163function Render :width (icon_width )
132- local text_width = nil
164+ local width = icon_width
133165 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' ))
135167 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 ))
137169 end
138- local width = icon_width + text_width
139170 local left_padding = self .context :resolve_offset (self .data .left_pad , width )
140171 local right_padding = self .context :resolve_offset (self .data .right_pad , width )
141172 width = math.max (left_padding + width + right_padding , self .data .min_width )
@@ -159,7 +190,7 @@ function Render:background(width)
159190 win_col = width .margin + width .content + self :indent (self .data .level )
160191 table.insert (padding , self :padding_text (vim .o .columns * 2 ))
161192 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
163194 self .marks :add (' head_background' , row , 0 , {
164195 end_row = row + 1 ,
165196 hl_group = highlight ,
179210--- @private
180211--- @param width render.md.width.Heading
181212function 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
184214 return
185215 end
186216
@@ -226,13 +256,13 @@ function Render:border(width)
226256
227257 local line_below = line (self .heading .below )
228258 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 , {
230260 virt_text = line_below ,
231261 virt_text_pos = ' overlay' ,
232262 })
233- self .context .last_heading = self .node .end_row + 1
263+ self .context .last_heading = self .node .end_row
234264 else
235- self .marks :add (false , self .node .end_row , 0 , {
265+ self .marks :add (false , self .node .start_row , 0 , {
236266 virt_lines = { self :indent_virt_line (line_below , self .data .level ) },
237267 })
238268 end
@@ -256,27 +286,21 @@ function Render:left_pad(width)
256286 if width .padding > 0 then
257287 table.insert (virt_text , self :padding_text (width .padding , self .data .background ))
258288 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+ })
267298 end
268299end
269300
270301--- @private
271302function 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 , {
280304 conceal = ' ' ,
281305 })
282306end
0 commit comments