Skip to content

Commit 2a16514

Browse files
authored
chore!: error handling (#285)
This adds error handling to the plugin, implemented with the help of `assert` and `xpcall`. Adding explicit error handling for the following cases for now: - Invalid commenstring / Commenting is not supported like `json` - When filetype doesn't support block comments like `yaml` - Graceful handling of certain cases like uncommenting when there is nothing to uncomment. --- fixes #221 supersedes #277
1 parent 5f01c1a commit 2a16514

File tree

4 files changed

+35
-16
lines changed

4 files changed

+35
-16
lines changed

lua/Comment/api.lua

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ local A = vim.api
1313

1414
local api, core = {}, {}
1515

16+
---API metamethods
17+
---@param that table
18+
---@param ctype CommentType
19+
---@return table
1620
function core.__index(that, ctype)
1721
local idxd = {}
1822
local mode, type = that.cmode, U.ctype[ctype]
@@ -22,25 +26,25 @@ function core.__index(that, ctype)
2226
---In current-line linewise method, 'opmode' is not useful which is always equals to `char`
2327
---but we need 'nil' here which is used for current-line
2428
function idxd.current(_, cfg)
25-
Op.opfunc(nil, cfg or Config:get(), mode, type)
29+
U.catch(Op.opfunc, nil, cfg or Config:get(), mode, type)
2630
end
2731

2832
---To comment lines with a count
2933
function idxd.count(count, cfg)
30-
Op.count(count or A.nvim_get_vvar('count'), cfg or Config:get(), mode, type)
34+
U.catch(Op.count, count or A.nvim_get_vvar('count'), cfg or Config:get(), mode, type)
3135
end
3236

3337
---@private
3438
---To comment lines with a count, also dot-repeatable
35-
---WARNING: This is not part of the API but anyone case use it, if they want
39+
---WARN: This is not part of the API but anyone case use it, if they want
3640
function idxd.count_repeat(_, count, cfg)
3741
idxd.count(count, cfg)
3842
end
3943

4044
return setmetatable({}, {
4145
__index = idxd,
4246
__call = function(_, motion, cfg)
43-
Op.opfunc(motion, cfg or Config:get(), mode, type)
47+
U.catch(Op.opfunc, motion, cfg or Config:get(), mode, type)
4448
end,
4549
})
4650
end
@@ -173,13 +177,13 @@ api.insert = setmetatable({}, {
173177
__index = function(_, ctype)
174178
return {
175179
above = function(cfg)
176-
Ex.insert_above(U.ctype[ctype], cfg or Config:get())
180+
U.catch(Ex.insert_above, U.ctype[ctype], cfg or Config:get())
177181
end,
178182
below = function(cfg)
179-
Ex.insert_below(U.ctype[ctype], cfg or Config:get())
183+
U.catch(Ex.insert_below, U.ctype[ctype], cfg or Config:get())
180184
end,
181185
eol = function(cfg)
182-
Ex.insert_eol(U.ctype[ctype], cfg or Config:get())
186+
U.catch(Ex.insert_eol, U.ctype[ctype], cfg or Config:get())
183187
end,
184188
}
185189
end,

lua/Comment/ft.lua

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,12 @@ function ft.get(lang, ctype)
193193
if not ctype then
194194
return vim.deepcopy(tuple)
195195
end
196-
return tuple[ctype]
196+
local cmt_str = tuple[ctype]
197+
assert(
198+
cmt_str or (ctype ~= require('Comment.utils').ctype.blockwise),
199+
{ msg = lang .. " doesn't support block comments!" }
200+
)
201+
return cmt_str
197202
end
198203

199204
---Get a language tree for a given range by walking the parse tree recursively.

lua/Comment/opfunc.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,14 @@ function Op.linewise(param)
171171
local uncomment = U.uncommenter(param.lcs, param.rcs, padding)
172172
for i, line in ipairs(param.lines) do
173173
if not U.ignore(line, pattern) then
174-
param.lines[i] = uncomment(line)
174+
param.lines[i] = uncomment(line) --[[@as string]]
175175
end
176176
end
177177
else
178178
local comment = U.commenter(param.lcs, param.rcs, padding, min_indent, nil, tabbed)
179179
for i, line in ipairs(param.lines) do
180180
if not U.ignore(line, pattern) then
181-
param.lines[i] = comment(line)
181+
param.lines[i] = comment(line) --[[@as string]]
182182
end
183183
end
184184
end

lua/Comment/utils.lua

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---@mod comment.utils Utilities
22

3-
local F = require('Comment.ft')
43
local A = vim.api
54

65
local U = {}
@@ -89,7 +88,7 @@ end
8988

9089
---@private
9190
---Call a function if exists
92-
---@param fn unknown|fun():unknown Wanna be function
91+
---@param fn unknown|fun(...):unknown Wanna be function
9392
---@return unknown
9493
function U.is_fn(fn, ...)
9594
if type(fn) == 'function' then
@@ -156,7 +155,7 @@ function U.unwrap_cstr(cstr)
156155

157156
assert(
158157
(left or right),
159-
string.format("[Comment] Invalid commentstring - %q. Run ':h commentstring' for help.", cstr)
158+
{ msg = string.format('Invalid commentstring for %s! Read `:h commentstring` for help.', vim.bo.filetype) }
160159
)
161160

162161
return vim.trim(left), vim.trim(right)
@@ -174,7 +173,7 @@ function U.parse_cstr(cfg, ctx)
174173
-- 1. We ask `pre_hook` for a commentstring
175174
local cstr = U.is_fn(cfg.pre_hook, ctx)
176175
-- 2. Calculate w/ the help of treesitter
177-
or F.calculate(ctx)
176+
or require('Comment.ft').calculate(ctx)
178177
-- 3. Last resort to use native commentstring
179178
or vim.bo.commentstring
180179

@@ -211,8 +210,8 @@ function U.commenter(left, right, padding, scol, ecol, tabbed)
211210
if scol == 0 then
212211
return (ll .. line .. rr)
213212
end
214-
local first = string.sub(line, 0, scol)
215-
local last = string.sub(line, scol + 1, -1)
213+
local first = string.sub(line --[[@as string]], 0, scol)
214+
local last = string.sub(line --[[@as string]], scol + 1, -1)
216215
return first .. ll .. last .. rr
217216
end
218217

@@ -294,6 +293,8 @@ function U.uncommenter(left, right, padding, scol, ecol)
294293
------------------
295294
if is_lw then
296295
local a, b, c = string.match(line, pattern)
296+
-- When user tries to uncomment when there is nothing to uncomment. See #221
297+
assert(a and b, { msg = 'Nothing to uncomment!' })
297298
-- If there is nothing after LHS then just return ''
298299
-- bcz the line previously (before comment) was empty
299300
return U.is_empty(b) and b or a .. b .. (c or '')
@@ -359,4 +360,13 @@ function U.is_commented(left, right, padding, scol, ecol)
359360
end
360361
end
361362

363+
---@private
364+
---Error handler
365+
---@param ... unknown
366+
function U.catch(fn, ...)
367+
xpcall(fn, function(err)
368+
vim.notify(string.format('[Comment.nvim] %s', err.msg), vim.log.levels.WARN)
369+
end, ...)
370+
end
371+
362372
return U

0 commit comments

Comments
 (0)