Skip to content

Commit 4d8b603

Browse files
feat: add right aligned language hint
## Details Request: #73 Adds new field `code -> position` with valid values `left` & `right`. Default value of `left` results in no change to current behavior. Changing the value to right will move the language icon to align roughly with the right side of the longest line in the code block. There is slightly different positioning for `block` vs `full` widths.
1 parent 9725df2 commit 4d8b603

File tree

7 files changed

+104
-45
lines changed

7 files changed

+104
-45
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ require('render-markdown').setup({
247247
-- language: adds language icon to sign column if enabled and icon + name above code blocks
248248
-- full: normal + language
249249
style = 'full',
250+
-- Determines where language icon is rendered:
251+
-- right: Right side of code block
252+
-- left: Left side of code block
253+
position = 'left',
250254
-- An array of language names for which background highlighting will be disabled
251255
-- Likely because that language has background highlights itself
252256
disable_background = { 'diff' },
@@ -266,8 +270,9 @@ require('render-markdown').setup({
266270
above = '',
267271
-- Used below code blocks for thin border
268272
below = '',
269-
-- Highlight for code blocks & inline code
273+
-- Highlight for code blocks
270274
highlight = 'RenderMarkdownCode',
275+
-- Highlight for inline code
271276
highlight_inline = 'RenderMarkdownCodeInline',
272277
},
273278
dash = {
@@ -510,6 +515,10 @@ require('render-markdown').setup({
510515
-- language: adds language icon to sign column if enabled and icon + name above code blocks
511516
-- full: normal + language
512517
style = 'full',
518+
-- Determines where language icon is rendered:
519+
-- right: Right side of code block
520+
-- left: Left side of code block
521+
position = 'left',
513522
-- An array of language names for which background highlighting will be disabled
514523
-- Likely because that language has background highlights itself
515524
disable_background = { 'diff' },
@@ -529,8 +538,9 @@ require('render-markdown').setup({
529538
above = '',
530539
-- Used below code blocks for thin border
531540
below = '',
532-
-- Highlight for code blocks & inline code
541+
-- Highlight for code blocks
533542
highlight = 'RenderMarkdownCode',
543+
-- Highlight for inline code
534544
highlight_inline = 'RenderMarkdownCodeInline',
535545
},
536546
})

doc/render-markdown.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ Full Default Configuration ~
279279
-- language: adds language icon to sign column if enabled and icon + name above code blocks
280280
-- full: normal + language
281281
style = 'full',
282+
-- Determines where language icon is rendered:
283+
-- right: Right side of code block
284+
-- left: Left side of code block
285+
position = 'left',
282286
-- An array of language names for which background highlighting will be disabled
283287
-- Likely because that language has background highlights itself
284288
disable_background = { 'diff' },
@@ -298,8 +302,9 @@ Full Default Configuration ~
298302
above = '▄',
299303
-- Used below code blocks for thin border
300304
below = '▀',
301-
-- Highlight for code blocks & inline code
305+
-- Highlight for code blocks
302306
highlight = 'RenderMarkdownCode',
307+
-- Highlight for inline code
303308
highlight_inline = 'RenderMarkdownCodeInline',
304309
},
305310
dash = {
@@ -542,6 +547,10 @@ CODE BLOCKS *render-markdown-setup-code-blocks*
542547
-- language: adds language icon to sign column if enabled and icon + name above code blocks
543548
-- full: normal + language
544549
style = 'full',
550+
-- Determines where language icon is rendered:
551+
-- right: Right side of code block
552+
-- left: Left side of code block
553+
position = 'left',
545554
-- An array of language names for which background highlighting will be disabled
546555
-- Likely because that language has background highlights itself
547556
disable_background = { 'diff' },
@@ -561,8 +570,9 @@ CODE BLOCKS *render-markdown-setup-code-blocks*
561570
above = '▄',
562571
-- Used below code blocks for thin border
563572
below = '▀',
564-
-- Highlight for code blocks & inline code
573+
-- Highlight for code blocks
565574
highlight = 'RenderMarkdownCode',
575+
-- Highlight for inline code
566576
highlight_inline = 'RenderMarkdownCodeInline',
567577
},
568578
})

lua/render-markdown/handler/markdown.lua

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function M.code(config, buf, info)
177177
if not code.enabled or code.style == 'none' then
178178
return {}
179179
end
180-
local code_block = code_block_parser.parse(buf, info)
180+
local code_block = code_block_parser.parse(code, buf, info)
181181
if code_block == nil then
182182
return {}
183183
end
@@ -217,33 +217,52 @@ function M.language(config, buf, code_block, add_background)
217217
if code.sign then
218218
list.add_mark(marks, M.sign(config, info, icon, icon_highlight))
219219
end
220-
-- Requires inline extmarks
221-
if not util.has_10 then
222-
return marks, false
223-
end
224-
local icon_text = icon .. ' '
225-
if ts.hidden(buf, info) then
226-
-- Code blocks will pick up varying amounts of leading white space depending on the
227-
-- context they are in. This gets lumped into the delimiter node and as a result,
228-
-- after concealing, the extmark will be left shifted. Logic below accounts for this.
229-
icon_text = str.pad(code_block.leading_spaces, icon_text .. info.text)
230-
end
231220
local highlight = { icon_highlight }
232221
if add_background then
233222
table.insert(highlight, code.highlight)
234223
end
235-
---@type render.md.Mark
236-
local language_marker = {
237-
conceal = true,
238-
start_row = info.start_row,
239-
start_col = info.start_col,
240-
opts = {
241-
virt_text = { { icon_text, highlight } },
242-
virt_text_pos = 'inline',
243-
},
244-
}
245-
list.add_mark(marks, language_marker)
246-
return marks, true
224+
-- Requires inline extmarks
225+
if code.position == 'left' and util.has_10 then
226+
local icon_text = icon .. ' '
227+
if ts.hidden(buf, info) then
228+
-- Code blocks will pick up varying amounts of leading white space depending on the
229+
-- context they are in. This gets lumped into the delimiter node and as a result,
230+
-- after concealing, the extmark will be left shifted. Logic below accounts for this.
231+
icon_text = str.pad(code_block.leading_spaces, icon_text .. info.text)
232+
end
233+
---@type render.md.Mark
234+
local language_marker = {
235+
conceal = true,
236+
start_row = info.start_row,
237+
start_col = info.start_col,
238+
opts = {
239+
virt_text = { { icon_text, highlight } },
240+
virt_text_pos = 'inline',
241+
},
242+
}
243+
list.add_mark(marks, language_marker)
244+
return marks, true
245+
elseif code.position == 'right' then
246+
local icon_text = icon .. ' ' .. info.text
247+
local win_col = code_block.longest_line
248+
if code.width == 'block' then
249+
win_col = win_col - str.width(icon_text)
250+
end
251+
---@type render.md.Mark
252+
local language_marker = {
253+
conceal = true,
254+
start_row = info.start_row,
255+
start_col = 0,
256+
opts = {
257+
virt_text = { { icon_text, highlight } },
258+
virt_text_win_col = win_col,
259+
},
260+
}
261+
list.add_mark(marks, language_marker)
262+
return marks, true
263+
else
264+
return marks, false
265+
end
247266
end
248267

249268
---@private
@@ -255,19 +274,9 @@ end
255274
function M.code_background(config, buf, code_block, icon_added)
256275
local code = config.code
257276

258-
local width
259-
if code.width == 'block' then
260-
local lines = vim.api.nvim_buf_get_lines(buf, code_block.start_row, code_block.end_row, true)
261-
local code_width = vim.fn.max(vim.tbl_map(str.width, lines))
262-
width = code.left_pad + code_width + code.right_pad
263-
else
264-
width = context.get(buf):get_width()
265-
end
266-
267277
local marks = {}
268-
269278
if code.border == 'thin' then
270-
local border_width = width - code_block.col
279+
local border_width = code_block.width - code_block.col
271280
if not icon_added and ts.hidden(buf, code_block.code_info) and ts.hidden(buf, code_block.start_delim) then
272281
---@type render.md.Mark
273282
local start_mark = {
@@ -323,15 +332,13 @@ function M.code_background(config, buf, code_block, icon_added)
323332
start_col = 0,
324333
opts = {
325334
priority = 0,
326-
hl_mode = 'replace',
327335
virt_text = { { padding, 'Normal' } },
328-
virt_text_win_col = width,
336+
virt_text_win_col = code_block.width,
329337
},
330338
}
331339
list.add_mark(marks, block_background_mark)
332340
end
333341
end
334-
335342
return marks
336343
end
337344

lua/render-markdown/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ local M = {}
7878
---@field public enabled? boolean
7979
---@field public sign? boolean
8080
---@field public style? 'full'|'normal'|'language'|'none'
81+
---@field public position? 'left'|'right'
8182
---@field public disable_background? string[]
8283
---@field public left_pad? integer
8384
---@field public right_pad? integer
@@ -262,6 +263,10 @@ M.default_config = {
262263
-- language: adds language icon to sign column if enabled and icon + name above code blocks
263264
-- full: normal + language
264265
style = 'full',
266+
-- Determines where language icon is rendered:
267+
-- right: Right side of code block
268+
-- left: Left side of code block
269+
position = 'left',
265270
-- An array of language names for which background highlighting will be disabled
266271
-- Likely because that language has background highlights itself
267272
disable_background = { 'diff' },
@@ -281,8 +286,9 @@ M.default_config = {
281286
above = '',
282287
-- Used below code blocks for thin border
283288
below = '',
284-
-- Highlight for code blocks & inline code
289+
-- Highlight for code blocks
285290
highlight = 'RenderMarkdownCode',
291+
-- Highlight for inline code
286292
highlight_inline = 'RenderMarkdownCodeInline',
287293
},
288294
dash = {

lua/render-markdown/parser/code_block.lua

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local context = require('render-markdown.context')
12
local str = require('render-markdown.str')
23
local ts = require('render-markdown.ts')
34

@@ -9,28 +10,34 @@ local M = {}
910
---@field start_row integer
1011
---@field end_row integer
1112
---@field leading_spaces integer
13+
---@field longest_line integer
14+
---@field width integer
1215
---@field code_info? render.md.NodeInfo
1316
---@field language_info? render.md.NodeInfo
1417
---@field language? string
1518
---@field start_delim? render.md.NodeInfo
1619
---@field end_delim? render.md.NodeInfo
1720

21+
---@param config render.md.Code
1822
---@param buf integer
1923
---@param info render.md.NodeInfo
2024
---@return render.md.parsed.CodeBlock?
21-
function M.parse(buf, info)
25+
function M.parse(config, buf, info)
2226
-- Do not attempt to render single line code block
23-
if info.start_row == info.end_row - 1 then
27+
if info.end_row - info.start_row <= 1 then
2428
return nil
2529
end
2630
local code_info = ts.child(buf, info, 'info_string', info.start_row)
2731
local language_info = ts.child(buf, code_info, 'language', info.start_row)
32+
local longest_line, width = M.get_width(config, buf, info)
2833
---@type render.md.parsed.CodeBlock
2934
return {
3035
col = info.start_col,
3136
start_row = info.start_row,
3237
end_row = info.end_row,
3338
leading_spaces = str.leading_spaces(info.text),
39+
longest_line = longest_line,
40+
width = width,
3441
code_info = code_info,
3542
language_info = language_info,
3643
language = (language_info or {}).text,
@@ -39,4 +46,21 @@ function M.parse(buf, info)
3946
}
4047
end
4148

49+
---@private
50+
---@param config render.md.Code
51+
---@param buf integer
52+
---@param info render.md.NodeInfo
53+
---@return integer
54+
---@return integer
55+
function M.get_width(config, buf, info)
56+
local lines = vim.api.nvim_buf_get_lines(buf, info.start_row, info.end_row, true)
57+
local code_width = vim.fn.max(vim.tbl_map(str.width, lines))
58+
local longest_line = config.left_pad + code_width + config.right_pad
59+
if config.width == 'block' then
60+
return longest_line, longest_line
61+
else
62+
return longest_line, context.get(buf):get_width()
63+
end
64+
end
65+
4266
return M

lua/render-markdown/state.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ function M.validate()
177177
enabled = { code.enabled, 'boolean', nilable },
178178
sign = { code.sign, 'boolean', nilable },
179179
style = one_of(code.style, { 'full', 'normal', 'language', 'none' }, {}, nilable),
180+
position = one_of(code.position, { 'left', 'right' }, {}, nilable),
180181
disable_background = string_array(code.disable_background, nilable),
181182
left_pad = { code.left_pad, 'number', nilable },
182183
right_pad = { code.right_pad, 'number', nilable },

lua/render-markdown/types.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
---@field public enabled boolean
6868
---@field public sign boolean
6969
---@field public style 'full'|'normal'|'language'|'none'
70+
---@field public position 'left'|'right'
7071
---@field public disable_background string[]
7172
---@field public left_pad integer
7273
---@field public right_pad integer

0 commit comments

Comments
 (0)