From a7097f372ba8f8866cda5e98d5bc828f2856c96c Mon Sep 17 00:00:00 2001 From: MeanderingProgrammer Date: Thu, 5 Dec 2024 16:31:23 -0800 Subject: [PATCH] feat: add default icons for ordered lists ## Details Request: https://github.com/MeanderingProgrammer/render-markdown.nvim/issues/250 Previously we supported adding icons for ordered lists in much the same way as unordered, however by default the value was empty. To do an auto ordering for the pattern of using `1.` for every value we now provide a default value. However, because ordered lists can go on and we want to support arbitrary lengths we now also support setting a function for both ordered and unordered list icons. The function is called with both the level of the list and the index of the item and whatever value is returned is used as the icon. The default function just concatenates a period after the index value and ignores the level. --- README.md | 32 +++++++++++++++------- doc/render-markdown.txt | 34 ++++++++++++++++-------- lua/render-markdown/health.lua | 2 +- lua/render-markdown/init.lua | 22 ++++++++++----- lua/render-markdown/render/list_item.lua | 12 ++++++--- lua/render-markdown/state.lua | 2 +- lua/render-markdown/types.lua | 4 +-- tests/list_table_spec.lua | 7 ++++- tests/util.lua | 14 ++++++++++ 9 files changed, 93 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 215ae9a..14e1558 100644 --- a/README.md +++ b/README.md @@ -362,14 +362,20 @@ require('render-markdown').setup({ -- Turn on / off list bullet rendering enabled = true, -- Replaces '-'|'+'|'*' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index -- If the item is a 'checkbox' a conceal is used to hide the bullet instead icons = { '●', '○', '◆', '◇' }, -- Replaces 'n.'|'n)' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list - ordered_icons = {}, + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index + ordered_icons = function(level, index) + return string.format('%d.', index) + end, -- Padding to add to the left of bullet point left_pad = 0, -- Padding to add to the right of bullet point @@ -859,14 +865,20 @@ require('render-markdown').setup({ -- Turn on / off list bullet rendering enabled = true, -- Replaces '-'|'+'|'*' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index -- If the item is a 'checkbox' a conceal is used to hide the bullet instead icons = { '●', '○', '◆', '◇' }, -- Replaces 'n.'|'n)' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list - ordered_icons = {}, + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index + ordered_icons = function(level, index) + return string.format('%d.', index) + end, -- Padding to add to the left of bullet point left_pad = 0, -- Padding to add to the right of bullet point diff --git a/doc/render-markdown.txt b/doc/render-markdown.txt index 1b4d2b2..fbeafa4 100644 --- a/doc/render-markdown.txt +++ b/doc/render-markdown.txt @@ -1,4 +1,4 @@ -*render-markdown.txt* For 0.10.0 Last change: 2024 December 04 +*render-markdown.txt* For 0.10.0 Last change: 2024 December 05 ============================================================================== Table of Contents *render-markdown-table-of-contents* @@ -409,14 +409,20 @@ Default Configuration ~ -- Turn on / off list bullet rendering enabled = true, -- Replaces '-'|'+'|'*' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index -- If the item is a 'checkbox' a conceal is used to hide the bullet instead icons = { '●', '○', '◆', '◇' }, -- Replaces 'n.'|'n)' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list - ordered_icons = {}, + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index + ordered_icons = function(level, index) + return string.format('%d.', index) + end, -- Padding to add to the left of bullet point left_pad = 0, -- Padding to add to the right of bullet point @@ -896,14 +902,20 @@ Bullet Point Configuration ~ -- Turn on / off list bullet rendering enabled = true, -- Replaces '-'|'+'|'*' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index -- If the item is a 'checkbox' a conceal is used to hide the bullet instead icons = { '●', '○', '◆', '◇' }, -- Replaces 'n.'|'n)' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list - ordered_icons = {}, + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index + ordered_icons = function(level, index) + return string.format('%d.', index) + end, -- Padding to add to the left of bullet point left_pad = 0, -- Padding to add to the right of bullet point diff --git a/lua/render-markdown/health.lua b/lua/render-markdown/health.lua index 493b50a..dbcf997 100644 --- a/lua/render-markdown/health.lua +++ b/lua/render-markdown/health.lua @@ -4,7 +4,7 @@ local state = require('render-markdown.state') local M = {} ---@private -M.version = '7.6.10' +M.version = '7.6.11' function M.check() M.start('version') diff --git a/lua/render-markdown/init.lua b/lua/render-markdown/init.lua index 0325a81..20f1f4a 100644 --- a/lua/render-markdown/init.lua +++ b/lua/render-markdown/init.lua @@ -127,10 +127,12 @@ local M = {} ---@field public checked? render.md.UserCheckboxComponent ---@field public custom? table +---@alias render.md.bullet.Icons string[]|string[][]|fun(level: integer, index: integer): string? + ---@class (exact) render.md.UserBullet ---@field public enabled? boolean ----@field public icons? (string|string[])[] ----@field public ordered_icons? (string|string[])[] +---@field public icons? render.md.bullet.Icons +---@field public ordered_icons? render.md.bullet.Icons ---@field public left_pad? integer ---@field public right_pad? integer ---@field public highlight? string @@ -494,14 +496,20 @@ M.default_config = { -- Turn on / off list bullet rendering enabled = true, -- Replaces '-'|'+'|'*' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index -- If the item is a 'checkbox' a conceal is used to hide the bullet instead icons = { '●', '○', '◆', '◇' }, -- Replaces 'n.'|'n)' of 'list_item' - -- How deeply nested the list is determines the 'level' which is used to index into the list using a cycle - -- The item number in the list is used to index into the value using a clamp if the value is also a list - ordered_icons = {}, + -- How deeply nested the list is determines the 'level', how far down at that level determines the 'index' + -- If a function is provided both of these values are passed in using 1 based indexing + -- If a list is provided we index into it using a cycle based on the level + -- If the value at that level is also a list we further index into it using a clamp based on the index + ordered_icons = function(level, index) + return string.format('%d.', index) + end, -- Padding to add to the left of bullet point left_pad = 0, -- Padding to add to the right of bullet point diff --git a/lua/render-markdown/render/list_item.lua b/lua/render-markdown/render/list_item.lua index 4ac4efb..8871d78 100644 --- a/lua/render-markdown/render/list_item.lua +++ b/lua/render-markdown/render/list_item.lua @@ -87,10 +87,16 @@ end ---@private ---@param level integer function Render:icon(level) + local index = self.node:sibling_count('list_item') local icons = self.data.ordered and self.bullet.ordered_icons or self.bullet.icons - local icon = List.cycle(icons, level) - if type(icon) == 'table' then - icon = List.clamp(icon, self.node:sibling_count('list_item')) + local icon = nil + if type(icons) == 'function' then + icon = icons(level, index) + else + icon = List.cycle(icons, level) + if type(icon) == 'table' then + icon = List.clamp(icon, index) + end end if icon == nil then return diff --git a/lua/render-markdown/state.lua b/lua/render-markdown/state.lua index 4684c2b..3eafaa8 100644 --- a/lua/render-markdown/state.lua +++ b/lua/render-markdown/state.lua @@ -189,7 +189,7 @@ function M.validate() :type('enabled', 'boolean') :type({ 'left_pad', 'right_pad' }, 'number') :type('highlight', 'string') - :list_or_list_of_list({ 'icons', 'ordered_icons' }, 'string') + :list_or_list_of_list({ 'icons', 'ordered_icons' }, 'string', 'function') :check() end) :nested('checkbox', function(checkbox) diff --git a/lua/render-markdown/types.lua b/lua/render-markdown/types.lua index 02fc200..d3e26db 100644 --- a/lua/render-markdown/types.lua +++ b/lua/render-markdown/types.lua @@ -110,8 +110,8 @@ ---@class (exact) render.md.Bullet ---@field public enabled boolean ----@field public icons (string|string[])[] ----@field public ordered_icons (string|string[])[] +---@field public icons render.md.bullet.Icons +---@field public ordered_icons render.md.bullet.Icons ---@field public left_pad integer ---@field public right_pad integer ---@field public highlight string diff --git a/tests/list_table_spec.lua b/tests/list_table_spec.lua index 794c466..da02b7a 100644 --- a/tests/list_table_spec.lua +++ b/tests/list_table_spec.lua @@ -26,7 +26,12 @@ describe('list_table.md', function() vim.list_extend(expected, util.heading(row:increment(2), 1)) - vim.list_extend(expected, util.heading(row:increment(5), 1)) + vim.list_extend(expected, { + util.ordered(row:increment(2), 0, '1.'), + util.ordered(row:increment(1), 0, '2.'), + }) + + vim.list_extend(expected, util.heading(row:increment(2), 1)) vim.list_extend(expected, { util.table_border(row:increment(2), true, { 8, 15, 7, 6 }), diff --git a/tests/util.lua b/tests/util.lua index 5f78dec..d6d13d0 100644 --- a/tests/util.lua +++ b/tests/util.lua @@ -165,6 +165,20 @@ function M.bullet(row, col, level, spaces) } end +---@param row integer +---@param col integer +---@param text string +---@return render.md.MarkInfo +function M.ordered(row, col, text) + ---@type render.md.MarkInfo + return { + row = { row, row }, + col = { col, col + 3 }, + virt_text = { { text, M.hl('Bullet') } }, + virt_text_pos = 'overlay', + } +end + ---@param row integer ---@param start_col integer ---@param end_col integer