Skip to content

Commit 04e75a3

Browse files
feat: allow bullet icons to be a list of lists
## Details Request: #217 This allows each icon for a bullet to itself be a list of strings. This list is indexed into using the sibling level of the list item. Sibling level just means which item number is this in the current list. So you can do something like roman numerals for level 1 and the alphabet for level 2. The list is accessed via a clamp so if we exceed the end we keep using the last value rather than cycling back to the front. Unrelated change, add a screenshot next to the gifs, see how that looks, might remove it.
1 parent 435b1ed commit 04e75a3

File tree

14 files changed

+127
-40
lines changed

14 files changed

+127
-40
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.gif
2+
*.png
23
/temp/

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ Plugin to improve viewing Markdown files in Neovim
44

55
<!-- panvimdoc-ignore-start -->
66

7-
| | |
8-
| --------- | ------- |
9-
| ![Heading](https://github.com/user-attachments/assets/6184ea2d-1769-4c37-bdc4-e6b0d1ca5c00) | ![Table](https://github.com/user-attachments/assets/328473e7-450a-4f52-bc0e-02ccc85e6268) |
10-
| ![Quote](https://github.com/user-attachments/assets/e7da67bc-7a3f-49f0-b8f6-3e61cf59197b) | ![LaTeX](https://github.com/user-attachments/assets/58da917b-5ca5-4705-9cad-978e7bb8574a) |
11-
| ![Callout](https://github.com/user-attachments/assets/73253fa4-ff4f-4562-a721-30c0a218c280) | |
7+
| Screenshot | Video |
8+
| ---------- | --------- |
9+
| ![Heading](https://github.com/user-attachments/assets/36f0fbb6-99bc-4cb2-8f69-fbea3d10abf1) | ![Heading](https://github.com/user-attachments/assets/e57a53ea-f0bf-48db-90c1-0c2365ab3c54) |
10+
| ![Table](https://github.com/user-attachments/assets/cbb81758-820d-467c-bc44-07003cb532bb) | ![Table](https://github.com/user-attachments/assets/5cd2b69d-ef17-4c6e-9510-59ed10e385d5) |
11+
| ![Quote](https://github.com/user-attachments/assets/822ae62c-bc0f-40a7-b8bb-fb3a885a95f9) | ![Quote](https://github.com/user-attachments/assets/aa002ac7-b30f-4079-bba9-505160a4ad78) |
12+
| ![Callout](https://github.com/user-attachments/assets/397ddd7b-bb82-47d0-ad9d-bdbe2f9858d7) | ![Callout](https://github.com/user-attachments/assets/250aaeda-6141-4f4c-b72c-103875ca6eb8) |
13+
| ![LaTeX](https://github.com/user-attachments/assets/7b859c0a-1bf6-4398-88b5-7bcde12f2390) | ![LaTeX](https://github.com/user-attachments/assets/9ef14030-f688-47fd-95ff-befab1253322) |
1214

1315
<!-- panvimdoc-ignore-end -->
1416

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 = 66
7+
local base_marks = 73
88
util.less_than(util.setup('README.md'), 50)
99
util.num_marks(base_marks)
1010

demo/format.tape

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ Sleep 2s
1717

1818
WRITE
1919

20-
Type "i" Sleep 1s
21-
Escape Sleep 1s
20+
Down
21+
Type "i" Sleep 0.5s
22+
Screenshot default.png Sleep 0.5s
23+
Escape Sleep 0.5s
24+
Screenshot rendered.png Sleep 0.5s
2225

2326
MOVE
2427

2528
Type "i" Sleep 1s
2629
Escape Sleep 1s
2730

2831
# Close without editing
29-
Type ":q!"
3032
Hide
33+
Type ":q!"
3134
Enter
3235
Sleep 100ms

demo/run.py

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from argparse import ArgumentParser
33
from pathlib import Path
44

5+
from PIL import Image
6+
57
INFO: dict[str, tuple[int, str]] = dict(
68
heading_code=(550, "## Heading 2"),
79
list_table=(550, ""),
@@ -12,31 +14,58 @@
1214

1315

1416
def main(name: str) -> None:
15-
in_file = Path(f"demo/{name}.md")
16-
assert in_file.exists()
17+
file = Path(f"demo/{name}.md")
18+
assert file.exists()
19+
20+
create_gif(name, file)
21+
create_screenshot(name)
22+
1723

18-
out_file = Path(f"demo/{name}.gif")
19-
if out_file.exists():
20-
out_file.unlink()
24+
def create_gif(name: str, file: Path) -> None:
25+
gif = Path(f"demo/{name}.gif")
26+
if gif.exists():
27+
gif.unlink()
2128

2229
height, content = INFO[name]
2330

2431
tape = Path("demo/demo.tape")
25-
tape.write_text(tape_content(in_file, out_file, height, content))
32+
tape.write_text(tape_content(file, gif, height, content))
2633
result = subprocess.run(["vhs", tape])
2734
assert result.returncode == 0
2835
tape.unlink()
2936

3037

31-
def tape_content(in_file: Path, out_file: Path, height: int, to_write: str) -> str:
32-
content = Path("demo/format.tape").read_text()
33-
content = content.replace("INPUT", str(in_file))
34-
content = content.replace("OUTPUT", str(out_file))
35-
content = content.replace("WIDTH", str(550))
36-
content = content.replace("HEIGHT", str(height))
37-
content = content.replace("WRITE", get_write(to_write))
38-
content = content.replace("MOVE", get_move(in_file))
39-
return content
38+
def create_screenshot(name: str) -> None:
39+
screenshot = Path(f"demo/{name}.png")
40+
if screenshot.exists():
41+
screenshot.unlink()
42+
43+
default, rendered = Path("default.png"), Path("rendered.png")
44+
assert default.exists() and rendered.exists()
45+
46+
left, right = Image.open(default), Image.open(rendered)
47+
48+
mode, width, height = left.mode, left.width, left.height
49+
assert mode == right.mode and width == right.width and height == right.height
50+
51+
combined = Image.new(mode, (2 * width, height))
52+
combined.paste(left, (0, 0))
53+
combined.paste(right, (width, 0))
54+
combined.save(screenshot)
55+
56+
default.unlink()
57+
rendered.unlink()
58+
59+
60+
def tape_content(file: Path, gif: Path, height: int, content: str) -> str:
61+
result = Path("demo/format.tape").read_text()
62+
result = result.replace("INPUT", str(file))
63+
result = result.replace("OUTPUT", str(gif))
64+
result = result.replace("WIDTH", str(550))
65+
result = result.replace("HEIGHT", str(height))
66+
result = result.replace("WRITE", get_write(content))
67+
result = result.replace("MOVE", get_move(file))
68+
return result
4069

4170

4271
def get_write(content: str) -> str:
@@ -49,10 +78,10 @@ def get_write(content: str) -> str:
4978
return "\n".join(write)
5079

5180

52-
def get_move(in_file: Path) -> str:
81+
def get_move(file: Path) -> str:
5382
move: list[str] = []
54-
# Get lines so we know how to scroll down, account for starting on first line
55-
lines: list[str] = Path(in_file).read_text().splitlines()[1:]
83+
# Get lines so we know how to scroll down, account for starting on second line
84+
lines: list[str] = file.read_text().splitlines()[2:]
5685
for line in lines:
5786
skip = (" ", "def", "if")
5887
duration = 0.1 if line == "" or line.startswith(skip) else 0.75

doc/render-markdown.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*render-markdown.txt* For 0.10.0 Last change: 2024 October 24
1+
*render-markdown.txt* For 0.10.0 Last change: 2024 October 25
22

33
==============================================================================
44
Table of Contents *render-markdown-table-of-contents*

lua/render-markdown/debug/validator.lua

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function Spec:list(keys, list_type, input_types)
7979
elseif type(v) == 'table' then
8080
for i, item in ipairs(v) do
8181
if type(item) ~= list_type then
82-
return false, string.format('Index %d is %s', i, type(item))
82+
return false, string.format('[%d] is %s', i, type(item))
8383
end
8484
end
8585
return true
@@ -89,6 +89,34 @@ function Spec:list(keys, list_type, input_types)
8989
end, list_type .. ' list' .. suffix)
9090
end
9191

92+
---@param keys string|string[]
93+
---@param list_type type
94+
---@param input_types? type|type[]
95+
---@return render.md.debug.ValidatorSpec
96+
function Spec:list_or_list_of_list(keys, list_type, input_types)
97+
local types, suffix = self:handle_types(input_types)
98+
return self:add(keys, function(v)
99+
if vim.tbl_contains(types, type(v)) then
100+
return true
101+
elseif type(v) == 'table' then
102+
for i, item in ipairs(v) do
103+
if type(item) == 'table' then
104+
for j, nested in ipairs(item) do
105+
if type(nested) ~= list_type then
106+
return false, string.format('[%d][%d] is %s', i, j, type(nested))
107+
end
108+
end
109+
elseif type(item) ~= list_type then
110+
return false, string.format('[%d] is %s', i, type(item))
111+
end
112+
end
113+
return true
114+
else
115+
return false
116+
end
117+
end, list_type .. ' list or list of list' .. suffix)
118+
end
119+
92120
---@param keys string|string[]
93121
---@param values string[]
94122
---@param input_types? type|type[]
@@ -103,7 +131,7 @@ function Spec:one_or_list_of(keys, values, input_types)
103131
elseif type(v) == 'table' then
104132
for i, item in ipairs(v) do
105133
if not vim.tbl_contains(values, item) then
106-
return false, string.format('Index %d is %s', i, item)
134+
return false, string.format('[%d] is %s', i, item)
107135
end
108136
end
109137
return true

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.4.7'
7+
M.version = '7.4.8'
88

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

lua/render-markdown/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ local M = {}
110110

111111
---@class (exact) render.md.UserBullet
112112
---@field public enabled? boolean
113-
---@field public icons? string[]
113+
---@field public icons? (string|string[])[]
114114
---@field public left_pad? integer
115115
---@field public right_pad? integer
116116
---@field public highlight? string

lua/render-markdown/lib/node.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,17 @@ function Node:sibling(target)
103103
return nil
104104
end
105105

106+
---@param target string
107+
---@return integer
108+
function Node:sibling_count(target)
109+
local count, sibling = 1, self.node:prev_sibling()
110+
while sibling ~= nil and sibling:type() == target do
111+
count = count + 1
112+
sibling = sibling:prev_sibling()
113+
end
114+
return count
115+
end
116+
106117
---@param target_type string
107118
---@param target_row? integer
108119
---@return render.md.Node?

0 commit comments

Comments
 (0)