Skip to content

Commit 634acd5

Browse files
feat: render footnote text using superscripts
## Details Request: #241 When the contents of a link starts with the ^ symbol we'll now assume this is related to a footnote. When the footnote pattern is spotted we replace the link contents with a superscript equivalent when possible. There are some interesting gaps in the superscript glyphs, I do not know why they exist, but they exist for parens, 0-9, most of a-z, and also most of A-Z but both character sets have at least one missing glyph. This behavior can be disabled by setting `link.footnote.superscript` to `false`. Since the translation between base character and superscript is not based on a shared offset or anything easy like that we maintain a complete mapping of base character to superscript. If there are any missing characters in the mapping then we skip doing any sort of superscript rendering.
1 parent 3a319cd commit 634acd5

File tree

12 files changed

+196
-18
lines changed

12 files changed

+196
-18
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,11 @@ require('render-markdown').setup({
507507
link = {
508508
-- Turn on / off inline link icon rendering
509509
enabled = true,
510+
-- How to handle footnote links, start with a '^'
511+
footnote = {
512+
-- Replace value with superscript equivalent
513+
superscript = true,
514+
},
510515
-- Inlined with 'image' elements
511516
image = '󰥶 ',
512517
-- Inlined with 'email_autolink' elements
@@ -1050,6 +1055,11 @@ require('render-markdown').setup({
10501055
link = {
10511056
-- Turn on / off inline link icon rendering
10521057
enabled = true,
1058+
-- How to handle footnote links, start with a '^'
1059+
footnote = {
1060+
-- Replace value with superscript equivalent
1061+
superscript = true,
1062+
},
10531063
-- Inlined with 'image' elements
10541064
image = '󰥶 ',
10551065
-- Inlined with 'email_autolink' elements

benches/readme_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local util = require('benches.util')
44

55
describe('README.md', function()
66
it('default', function()
7-
local base_marks = 100
7+
local base_marks = 114
88
util.less_than(util.setup('README.md'), 60)
99
util.num_marks(base_marks)
1010

doc/render-markdown.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,11 @@ Default Configuration ~
554554
link = {
555555
-- Turn on / off inline link icon rendering
556556
enabled = true,
557+
-- How to handle footnote links, start with a '^'
558+
footnote = {
559+
-- Replace value with superscript equivalent
560+
superscript = true,
561+
},
557562
-- Inlined with 'image' elements
558563
image = '󰥶 ',
559564
-- Inlined with 'email_autolink' elements
@@ -1077,6 +1082,11 @@ Link Configuration ~
10771082
link = {
10781083
-- Turn on / off inline link icon rendering
10791084
enabled = true,
1085+
-- How to handle footnote links, start with a '^'
1086+
footnote = {
1087+
-- Replace value with superscript equivalent
1088+
superscript = true,
1089+
},
10801090
-- Inlined with 'image' elements
10811091
image = '󰥶 ',
10821092
-- Inlined with 'email_autolink' elements

lua/render-markdown/health.lua

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

66
---@private
7-
M.version = '7.6.1'
7+
M.version = '7.6.2'
88

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

lua/render-markdown/init.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@ local M = {}
5454
---@field public icon? string
5555
---@field public highlight? string
5656

57+
---@class (exact) render.md.UserFootnote
58+
---@field public superscript? boolean
59+
5760
---@class (exact) render.md.UserLink
5861
---@field public enabled? boolean
62+
---@field public footnote? render.md.UserFootnote
5963
---@field public image? string
6064
---@field public email? string
6165
---@field public hyperlink? string
@@ -625,6 +629,11 @@ M.default_config = {
625629
link = {
626630
-- Turn on / off inline link icon rendering
627631
enabled = true,
632+
-- How to handle footnote links, start with a '^'
633+
footnote = {
634+
-- Replace value with superscript equivalent
635+
superscript = true,
636+
},
628637
-- Inlined with 'image' elements
629638
image = '󰥶 ',
630639
-- Inlined with 'email_autolink' elements

lua/render-markdown/lib/converter.lua

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---@class render.md.Converter
2+
local M = {}
3+
4+
---@private
5+
M.superscripts = {
6+
[' '] = ' ',
7+
['('] = '',
8+
[')'] = '',
9+
10+
['0'] = '',
11+
['1'] = '¹',
12+
['2'] = '²',
13+
['3'] = '³',
14+
['4'] = '',
15+
['5'] = '',
16+
['6'] = '',
17+
['7'] = '',
18+
['8'] = '',
19+
['9'] = '',
20+
21+
['a'] = '',
22+
['b'] = '',
23+
['c'] = '',
24+
['d'] = '',
25+
['e'] = '',
26+
['f'] = '',
27+
['g'] = '',
28+
['h'] = 'ʰ',
29+
['i'] = '',
30+
['j'] = 'ʲ',
31+
['k'] = '',
32+
['l'] = 'ˡ',
33+
['m'] = '',
34+
['n'] = '',
35+
['o'] = '',
36+
['p'] = '',
37+
['q'] = nil,
38+
['r'] = 'ʳ',
39+
['s'] = 'ˢ',
40+
['t'] = '',
41+
['u'] = '',
42+
['v'] = '',
43+
['w'] = 'ʷ',
44+
['x'] = 'ˣ',
45+
['y'] = 'ʸ',
46+
['z'] = '',
47+
48+
['A'] = '',
49+
['B'] = '',
50+
['C'] = nil,
51+
['D'] = '',
52+
['E'] = '',
53+
['F'] = nil,
54+
['G'] = '',
55+
['H'] = '',
56+
['I'] = '',
57+
['J'] = '',
58+
['K'] = '',
59+
['L'] = '',
60+
['M'] = '',
61+
['N'] = '',
62+
['O'] = '',
63+
['P'] = '',
64+
['Q'] = nil,
65+
['R'] = 'ᴿ',
66+
['S'] = nil,
67+
['T'] = '',
68+
['U'] = '',
69+
['V'] = '',
70+
['W'] = '',
71+
['X'] = nil,
72+
['Y'] = nil,
73+
['Z'] = nil,
74+
}
75+
76+
---@param s string
77+
---@return string?
78+
function M.to_superscript(s)
79+
local chars = {}
80+
for char in s:gmatch('.') do
81+
char = M.superscripts[char]
82+
if char == nil then
83+
return nil
84+
end
85+
table.insert(chars, char)
86+
end
87+
return table.concat(chars)
88+
end
89+
90+
return M

lua/render-markdown/render/inline_highlight.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function Render:render()
1919
---@type integer|nil
2020
local index = 1
2121
while index ~= nil do
22-
local start_index, end_index = self.node.text:find('(=)=[^=]+=(=)', index)
22+
local start_index, end_index = self.node.text:find('==[^=]+==', index)
2323
if start_index == nil or end_index == nil then
2424
index = nil
2525
else

lua/render-markdown/render/shortcut.lua

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
local Base = require('render-markdown.render.base')
2+
local Converter = require('render-markdown.lib.converter')
23
local Str = require('render-markdown.lib.str')
34

45
---@class render.md.render.Shortcut: render.md.Renderer
6+
---@field private link render.md.Link
57
local Render = setmetatable({}, Base)
68
Render.__index = Render
79

810
---@return boolean
911
function Render:setup()
12+
self.link = self.config.link
1013
return true
1114
end
1215

@@ -28,6 +31,12 @@ function Render:render()
2831
self:wiki_link()
2932
return
3033
end
34+
35+
local _, _, text = self.node.text:find('^%[%^(.+)%]$')
36+
if text ~= nil then
37+
self:footnote(text)
38+
return
39+
end
3140
end
3241

3342
---@private
@@ -85,13 +94,13 @@ end
8594

8695
---@private
8796
function Render:wiki_link()
88-
if not self.config.link.enabled then
97+
if not self.link.enabled then
8998
return
9099
end
91100

92101
local parts = Str.split(self.node.text:sub(2, -2), '|')
93102
local link_component = self:link_component(parts[1])
94-
local icon, highlight = self.config.link.wiki.icon, self.config.link.wiki.highlight
103+
local icon, highlight = self.link.wiki.icon, self.link.wiki.highlight
95104
if link_component ~= nil then
96105
icon, highlight = link_component.icon, link_component.highlight
97106
end
@@ -103,4 +112,23 @@ function Render:wiki_link()
103112
}, { 0, -1, 0, 1 })
104113
end
105114

115+
---@private
116+
---@param text string
117+
function Render:footnote(text)
118+
if not self.link.enabled or not self.link.footnote.superscript then
119+
return
120+
end
121+
122+
local value = Converter.to_superscript('(' .. text .. ')')
123+
if value == nil then
124+
return
125+
end
126+
127+
self.marks:add_over('link', self.node, {
128+
virt_text = { { value, self.link.highlight } },
129+
virt_text_pos = 'inline',
130+
conceal = '',
131+
})
132+
end
133+
106134
return Render

lua/render-markdown/state.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ function M.validate()
194194
:nested('checkbox', function(checkbox)
195195
checkbox
196196
:type('enabled', 'boolean')
197-
:type('custom', 'table')
198197
:one_of('position', { 'overlay', 'inline' })
199198
:nested({ 'unchecked', 'checked' }, function(box)
200199
box:type({ 'icon', 'highlight' }, 'string'):type('scope_highlight', { 'string', 'nil' }):check()
@@ -235,7 +234,9 @@ function M.validate()
235234
:nested('link', function(link)
236235
link:type('enabled', 'boolean')
237236
:type({ 'image', 'email', 'hyperlink', 'highlight' }, 'string')
238-
:type({ 'wiki', 'custom' }, 'table')
237+
:nested('footnote', function(footnote)
238+
footnote:type('superscript', 'boolean'):check()
239+
end)
239240
:nested('wiki', function(wiki)
240241
wiki:type({ 'icon', 'highlight' }, 'string'):check()
241242
end)

lua/render-markdown/types.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@
4141
---@field public icon string
4242
---@field public highlight string
4343

44+
---@class (exact) render.md.Footnote
45+
---@field public superscript boolean
46+
4447
---@class (exact) render.md.Link
4548
---@field public enabled boolean
49+
---@field public footnote render.md.Footnote
4650
---@field public image string
4751
---@field public email string
4852
---@field public hyperlink string

0 commit comments

Comments
 (0)