Skip to content

Commit 7f81e9d

Browse files
feat: use selene to prevent accidental print statements
## Details After leaving a print statement in the last push, wanted an automated way to prevent this in the future. While there's no perfect solution I did come up with one that works well enough. Added a `selene.toml` with a `neovim` base. The base defines the `vim` global (as any) along with the various test framework globals like `describe`, `it`, and the various `assert` methods. Important for this change specifically it also marks both `print` and `vim.print` as deprecated. That way any usage of those functions fails the check. Where we do want to allow these methods add `selene: allow(deprecated)`. It's not accurate since the methods are not deprecated, but does allow me to quickly catch any usage that has not been explicitly allowed. Added a `check` step that runs both `selene` & `stylua` over all files. Fixed / improved a few issues: - caught an error where I defined `Providers` globally instead of locally - inline luassert `assert` methods so that errors are found - add allow for mixed table around minimal config - always provide a message argument to regular `assert` method
1 parent bff12b4 commit 7f81e9d

24 files changed

+115
-66
lines changed

benches/util.lua

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
---@module 'luassert'
22

3-
local Eq = assert.are.same
4-
local True = assert.True
5-
63
---@class render.md.bench.Util
74
local M = {}
85

@@ -53,14 +50,14 @@ end
5350
---@param actual number
5451
---@param max number
5552
function M.less_than(actual, max)
56-
True(actual < max, ('expected %f < %f'):format(actual, max))
53+
assert.is_true(actual < max, ('expected %f < %f'):format(actual, max))
5754
end
5855

5956
---@param expected integer
6057
function M.num_marks(expected)
6158
local ui = require('render-markdown.core.ui')
6259
local marks = vim.api.nvim_buf_get_extmarks(0, ui.ns, 0, -1, {})
63-
Eq(expected, #marks)
60+
assert.same(expected, #marks)
6461
end
6562

6663
return M

demo/minit.lua

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
1515
assert(vim.uv.fs_stat(lazypath))
1616
vim.opt.rtp:prepend(lazypath)
1717

18+
-- selene: allow(mixed_table)
1819
require('lazy').setup({
1920
dev = { path = '~/dev/repos/personal' },
2021
spec = {
@@ -32,7 +33,12 @@ require('lazy').setup({
3233
config = function()
3334
---@diagnostic disable-next-line: missing-fields
3435
require('nvim-treesitter.configs').setup({
35-
ensure_installed = { 'markdown', 'markdown_inline', 'latex' },
36+
ensure_installed = {
37+
'html',
38+
'latex',
39+
'markdown',
40+
'markdown_inline',
41+
},
3642
highlight = { enable = true },
3743
})
3844
end,
@@ -56,7 +62,10 @@ require('lazy').setup({
5662
{
5763
'MeanderingProgrammer/render-markdown.nvim',
5864
dev = true,
59-
dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' },
65+
dependencies = {
66+
'nvim-treesitter/nvim-treesitter',
67+
'echasnovski/mini.nvim',
68+
},
6069
config = function()
6170
require('render-markdown').setup({})
6271
end,

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 NVIM v0.11.1 Last change: 2025 April 28
1+
*render-markdown.txt* For NVIM v0.11.1 Last change: 2025 April 29
22

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

justfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
init := "tests/minimal_init.lua"
22

3-
default: update test health
3+
default: update check test health
44

55
update:
66
# Updates types.lua & README.md
@@ -11,6 +11,10 @@ update:
1111
--project-name render-markdown \
1212
--input-file README.md
1313

14+
check:
15+
selene --quiet .
16+
stylua --check .
17+
1418
test:
1519
just busted "tests"
1620

lua/render-markdown/api.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ end
4949
function M.config()
5050
local difference = state.difference()
5151
if difference == nil then
52+
-- selene: allow(deprecated)
5253
vim.print('default configuration')
5354
else
55+
-- selene: allow(deprecated)
5456
vim.print(difference)
5557
end
5658
end

lua/render-markdown/core/log.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ function M.runtime(name, callback)
5757
callback()
5858
local end_time = Compat.uv.hrtime()
5959
local elapsed = (end_time - start_time) / 1e+6
60-
assert(elapsed < 1000)
60+
assert(elapsed < 1000, 'invalid elapsed time')
61+
-- selene: allow(deprecated)
6162
vim.print(('%8s : %5.1f ms'):format(name:upper(), elapsed))
6263
end
6364
else

lua/render-markdown/debug/marks.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ end
2525
---@return boolean
2626
function Mark.__lt(a, b)
2727
local as, bs = a:priorities(), b:priorities()
28-
assert(#as == #bs)
28+
assert(#as == #bs, 'priorities must be same length')
2929
for i = 1, #as do
3030
if as[i] ~= bs[i] then
3131
return as[i] < bs[i]
@@ -166,10 +166,13 @@ function M.show()
166166
table.sort(marks)
167167

168168
if #marks == 0 then
169+
-- selene: allow(deprecated)
169170
vim.print(('no marks on row: %d'):format(row))
170171
else
172+
-- selene: allow(deprecated)
171173
vim.print(('marks on row: %d'):format(row))
172174
for _, mark in ipairs(marks) do
175+
-- selene: allow(deprecated)
173176
vim.print(tostring(mark))
174177
end
175178
end

lua/render-markdown/handler/html.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function Handler:parse(root)
3737
local marks = Marks.new(self.context, true)
3838
self.context:query(root, self.query, function(capture, node)
3939
local renderer = self.renderers[capture]
40-
assert(renderer ~= nil, 'Unhandled html capture: ' .. capture)
40+
assert(renderer ~= nil, 'unhandled html capture: ' .. capture)
4141
local render = renderer:new(self.context, marks, node)
4242
if render:setup() then
4343
render:render()

lua/render-markdown/handler/markdown.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function Handler:parse(root)
6969
local marks = Marks.new(self.context, false)
7070
self.context:query(root, self.query, function(capture, node)
7171
local renderer = self.renderers[capture]
72-
assert(renderer ~= nil, 'Unhandled markdown capture: ' .. capture)
72+
assert(renderer ~= nil, 'unhandled markdown capture: ' .. capture)
7373
local render = renderer:new(self.context, marks, node)
7474
if render:setup() then
7575
render:render()

lua/render-markdown/handler/markdown_inline.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function Handler:parse(root)
4848
local marks = Marks.new(self.context, true)
4949
self.context:query(root, self.query, function(capture, node)
5050
local renderer = self.renderers[capture]
51-
assert(renderer ~= nil, 'Unhandled inline capture: ' .. capture)
51+
assert(renderer ~= nil, 'unhandled inline capture: ' .. capture)
5252
local render = renderer:new(self.context, marks, node)
5353
if render:setup() then
5454
render:render()

lua/render-markdown/health.lua

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

77
---@private
8-
M.version = '8.3.18'
8+
M.version = '8.3.19'
99

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

lua/render-markdown/integ/coq.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function M.setup()
1717
if not has_coq then
1818
return
1919
end
20+
-- selene: allow(unscoped_variables)
2021
---@type table<integer, table>
2122
COQsources = COQsources or {}
2223
COQsources[M.new_uid(COQsources)] = {

lua/render-markdown/integ/icons.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
---@field get fun(filetype: string): string?, string?
44

55
---@class render.md.icon.Providers
6-
Providers = {}
6+
local Providers = {}
77

88
---@return render.md.icon.Provider?
99
function Providers.MiniIcons()
@@ -15,6 +15,7 @@ function Providers.MiniIcons()
1515
if getter == nil then
1616
return nil
1717
end
18+
-- selene: allow(global_usage)
1819
-- additional check recommended by author
1920
if _G.MiniIcons == nil then
2021
return nil

lua/render-markdown/lib/marks.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ function Marks:update(mark)
137137
end
138138
local row, start_col = mark.start_row, mark.start_col
139139
if mark.opts.conceal ~= nil then
140-
local end_col = assert(mark.opts.end_col)
140+
local end_col = assert(mark.opts.end_col, 'conceal requires end_col')
141141
self.context.conceal:add(row, {
142142
start_col = start_col,
143143
end_col = end_col,

lua/render-markdown/render/base.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ function Base:indent_line(virtual, level)
130130
if virtual then
131131
level = self:indent_level(level)
132132
else
133-
assert(level ~= nil, 'Level must be known for real lines')
133+
assert(level ~= nil, 'level must be known for real lines')
134134
end
135135
local line = {}
136136
if level > 0 then

neovim.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
base: lua51
3+
4+
globals:
5+
vim:
6+
any: true
7+
vim.print:
8+
args:
9+
- type: ...
10+
deprecated:
11+
message: accidental print
12+
print:
13+
args:
14+
- type: ...
15+
deprecated:
16+
message: accidental print
17+
describe:
18+
args:
19+
- type: string
20+
- type: function
21+
it:
22+
args:
23+
- type: string
24+
- type: function
25+
assert.same:
26+
args:
27+
- type: any
28+
- type: any
29+
- type: string
30+
required: false
31+
assert.is_true:
32+
args:
33+
- type: bool
34+
- type: string
35+
required: false
36+
assert.is_false:
37+
args:
38+
- type: bool
39+
- type: string
40+
required: false

selene.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
std = "neovim"
2+
3+
[config]
4+
empty_if = { comments_count = true }

tests/comp_spec.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
local util = require('tests.util')
44

5-
local Eq = assert.are.same
6-
75
---@param row integer
86
---@param col integer
97
---@param expected lsp.CompletionItem[]
@@ -13,7 +11,7 @@ local function assert_items(row, col, expected)
1311
table.sort(actual, function(a, b)
1412
return a.label < b.label
1513
end)
16-
Eq(expected, actual)
14+
assert.same(expected, actual)
1715
end
1816

1917
---@param prefix string

tests/helpers/details.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ end
7171
---@return boolean
7272
function MarkDetails.__lt(a, b)
7373
local as, bs = a:priorities(), b:priorities()
74-
assert(#as == #bs)
74+
assert(#as == #bs, 'priorities must be same length')
7575
for i = 1, #as do
7676
if as[i] ~= bs[i] then
7777
return as[i] < bs[i]

tests/latex_spec.lua

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,17 @@
33
local stub = require('luassert.stub')
44
local util = require('tests.util')
55

6-
local Eq = assert.are.same
7-
local True = assert.True
8-
96
---@param converter string
107
---@param responses table<string, string>
118
local function set_responses(converter, responses)
129
stub.new(vim.fn, 'executable', function(expr)
13-
Eq(converter, expr)
10+
assert.same(converter, expr)
1411
return 1
1512
end)
1613
stub.new(vim.fn, 'system', function(cmd, input)
17-
Eq(converter, cmd)
14+
assert.same(converter, cmd)
1815
local result = responses[input]
19-
True(result ~= nil, 'No output for: ' .. input)
16+
assert.is_true(result ~= nil, 'No output for: ' .. input)
2017
return result
2118
end)
2219
end

tests/minimal_init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
local function get_path(name)
44
local data_path = vim.fn.stdpath('data')
55
local plugin_path = vim.fs.find(name, { path = data_path })
6-
assert(#plugin_path == 1)
6+
assert(#plugin_path == 1, 'plugin must have one path')
77
return plugin_path[1]
88
end
99

tests/range_spec.lua

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,35 @@
22

33
local Range = require('render-markdown.core.range')
44

5-
local Eq = assert.are.same
6-
local True = assert.True
7-
local False = assert.False
8-
95
describe('range', function()
106
it('contains', function()
117
local range = Range.new(5, 9)
12-
True(range:contains(5, 9)) -- identity
13-
True(range:contains(6, 8)) -- inside
14-
False(range:contains(4, 10)) -- around
15-
False(range:contains(3, 4)) -- before
16-
False(range:contains(10, 11)) -- after
17-
False(range:contains(4, 9)) -- start -1
18-
False(range:contains(4, 8)) -- start & end -1
19-
False(range:contains(5, 10)) -- end +1
20-
False(range:contains(6, 10)) -- start & end +1
21-
False(range:contains(4, 5)) -- ends @ start
22-
False(range:contains(9, 10)) -- starts @ end
8+
assert.is_true(range:contains(5, 9)) -- identity
9+
assert.is_true(range:contains(6, 8)) -- inside
10+
assert.is_false(range:contains(4, 10)) -- around
11+
assert.is_false(range:contains(3, 4)) -- before
12+
assert.is_false(range:contains(10, 11)) -- after
13+
assert.is_false(range:contains(4, 9)) -- start -1
14+
assert.is_false(range:contains(4, 8)) -- start & end -1
15+
assert.is_false(range:contains(5, 10)) -- end +1
16+
assert.is_false(range:contains(6, 10)) -- start & end +1
17+
assert.is_false(range:contains(4, 5)) -- ends @ start
18+
assert.is_false(range:contains(9, 10)) -- starts @ end
2319
end)
2420

2521
it('overlaps', function()
2622
local range = Range.new(5, 9)
27-
True(range:overlaps(5, 9)) -- identity
28-
True(range:overlaps(6, 8)) -- inside
29-
True(range:overlaps(4, 10)) -- around
30-
False(range:overlaps(3, 4)) -- before
31-
False(range:overlaps(10, 11)) -- after
32-
True(range:overlaps(4, 9)) -- start -1
33-
True(range:overlaps(4, 8)) -- start & end -1
34-
True(range:overlaps(5, 10)) -- end +1
35-
True(range:overlaps(6, 10)) -- start & end +1
36-
True(range:overlaps(4, 5)) -- ends @ start
37-
True(range:overlaps(9, 10)) -- starts @ end
23+
assert.is_true(range:overlaps(5, 9)) -- identity
24+
assert.is_true(range:overlaps(6, 8)) -- inside
25+
assert.is_true(range:overlaps(4, 10)) -- around
26+
assert.is_false(range:overlaps(3, 4)) -- before
27+
assert.is_false(range:overlaps(10, 11)) -- after
28+
assert.is_true(range:overlaps(4, 9)) -- start -1
29+
assert.is_true(range:overlaps(4, 8)) -- start & end -1
30+
assert.is_true(range:overlaps(5, 10)) -- end +1
31+
assert.is_true(range:overlaps(6, 10)) -- start & end +1
32+
assert.is_true(range:overlaps(4, 5)) -- ends @ start
33+
assert.is_true(range:overlaps(9, 10)) -- starts @ end
3834
end)
3935

4036
it('coalesce', function()
@@ -51,6 +47,6 @@ describe('range', function()
5147
Range.new(12, 20),
5248
Range.new(25, 30),
5349
}
54-
Eq(expected, Range.coalesce(ranges))
50+
assert.same(expected, Range.coalesce(ranges))
5551
end)
5652
end)

0 commit comments

Comments
 (0)