From 5b4403e609bfdf65ed1d46fcf4c8ffc750f478b7 Mon Sep 17 00:00:00 2001
From: numToStr <vikasraj1911@gmail.com>
Date: Fri, 23 Dec 2022 19:02:17 +0530
Subject: [PATCH] fix!: error handling

---
 lua/Comment/api.lua    | 18 +++++++++++-------
 lua/Comment/ft.lua     |  4 +++-
 lua/Comment/opfunc.lua |  4 ++--
 lua/Comment/utils.lua  | 18 ++++++++++++++----
 4 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/lua/Comment/api.lua b/lua/Comment/api.lua
index b60c30c5..d990c6e5 100644
--- a/lua/Comment/api.lua
+++ b/lua/Comment/api.lua
@@ -13,6 +13,10 @@ local A = vim.api
 
 local api, core = {}, {}
 
+---API metamethods
+---@param that table
+---@param ctype CommentType
+---@return table
 function core.__index(that, ctype)
     local idxd = {}
     local mode, type = that.cmode, U.ctype[ctype]
@@ -22,17 +26,17 @@ function core.__index(that, ctype)
     ---In current-line linewise method, 'opmode' is not useful which is always equals to `char`
     ---but we need 'nil' here which is used for current-line
     function idxd.current(_, cfg)
-        Op.opfunc(nil, cfg or Config:get(), mode, type)
+        U.catch(Op.opfunc, nil, cfg or Config:get(), mode, type)
     end
 
     ---To comment lines with a count
     function idxd.count(count, cfg)
-        Op.count(count or A.nvim_get_vvar('count'), cfg or Config:get(), mode, type)
+        U.catch(Op.count, count or A.nvim_get_vvar('count'), cfg or Config:get(), mode, type)
     end
 
     ---@private
     ---To comment lines with a count, also dot-repeatable
-    ---WARNING: This is not part of the API but anyone case use it, if they want
+    ---WARN: This is not part of the API but anyone case use it, if they want
     function idxd.count_repeat(_, count, cfg)
         idxd.count(count, cfg)
     end
@@ -40,7 +44,7 @@ function core.__index(that, ctype)
     return setmetatable({}, {
         __index = idxd,
         __call = function(_, motion, cfg)
-            Op.opfunc(motion, cfg or Config:get(), mode, type)
+            U.catch(Op.opfunc, motion, cfg or Config:get(), mode, type)
         end,
     })
 end
@@ -173,13 +177,13 @@ api.insert = setmetatable({}, {
     __index = function(_, ctype)
         return {
             above = function(cfg)
-                Ex.insert_above(U.ctype[ctype], cfg or Config:get())
+                U.catch(Ex.insert_above, U.ctype[ctype], cfg or Config:get())
             end,
             below = function(cfg)
-                Ex.insert_below(U.ctype[ctype], cfg or Config:get())
+                U.catch(Ex.insert_below, U.ctype[ctype], cfg or Config:get())
             end,
             eol = function(cfg)
-                Ex.insert_eol(U.ctype[ctype], cfg or Config:get())
+                U.catch(Ex.insert_eol, U.ctype[ctype], cfg or Config:get())
             end,
         }
     end,
diff --git a/lua/Comment/ft.lua b/lua/Comment/ft.lua
index d03ed406..1da9c552 100644
--- a/lua/Comment/ft.lua
+++ b/lua/Comment/ft.lua
@@ -193,7 +193,9 @@ function ft.get(lang, ctype)
     if not ctype then
         return vim.deepcopy(tuple)
     end
-    return tuple[ctype]
+    local cmt_str = tuple[ctype]
+    assert(cmt_str or ctype ~= 2, { msg = lang .. " doesn't support block comments!" })
+    return cmt_str
 end
 
 ---Get a language tree for a given range by walking the parse tree recursively.
diff --git a/lua/Comment/opfunc.lua b/lua/Comment/opfunc.lua
index de4426c6..02585a63 100644
--- a/lua/Comment/opfunc.lua
+++ b/lua/Comment/opfunc.lua
@@ -171,14 +171,14 @@ function Op.linewise(param)
         local uncomment = U.uncommenter(param.lcs, param.rcs, padding)
         for i, line in ipairs(param.lines) do
             if not U.ignore(line, pattern) then
-                param.lines[i] = uncomment(line)
+                param.lines[i] = uncomment(line) --[[@as string]]
             end
         end
     else
         local comment = U.commenter(param.lcs, param.rcs, padding, min_indent, nil, tabbed)
         for i, line in ipairs(param.lines) do
             if not U.ignore(line, pattern) then
-                param.lines[i] = comment(line)
+                param.lines[i] = comment(line) --[[@as string]]
             end
         end
     end
diff --git a/lua/Comment/utils.lua b/lua/Comment/utils.lua
index f0d4ad43..34f87e80 100644
--- a/lua/Comment/utils.lua
+++ b/lua/Comment/utils.lua
@@ -89,7 +89,7 @@ end
 
 ---@private
 ---Call a function if exists
----@param fn unknown|fun():unknown Wanna be function
+---@param fn unknown|fun(...):unknown Wanna be function
 ---@return unknown
 function U.is_fn(fn, ...)
     if type(fn) == 'function' then
@@ -156,7 +156,7 @@ function U.unwrap_cstr(cstr)
 
     assert(
         (left or right),
-        string.format("[Comment] Invalid commentstring - %q. Run ':h commentstring' for help.", cstr)
+        { msg = string.format("Invalid commentstring - %q. Run ':h commentstring' for help!", cstr) }
     )
 
     return vim.trim(left), vim.trim(right)
@@ -211,8 +211,8 @@ function U.commenter(left, right, padding, scol, ecol, tabbed)
             if scol == 0 then
                 return (ll .. line .. rr)
             end
-            local first = string.sub(line, 0, scol)
-            local last = string.sub(line, scol + 1, -1)
+            local first = string.sub(line --[[@as string]], 0, scol)
+            local last = string.sub(line --[[@as string]], scol + 1, -1)
             return first .. ll .. last .. rr
         end
 
@@ -294,6 +294,8 @@ function U.uncommenter(left, right, padding, scol, ecol)
         ------------------
         if is_lw then
             local a, b, c = string.match(line, pattern)
+            -- When user tries to uncomment when there is nothing to uncomment. See #221
+            assert(a and b, { msg = 'Nothing to uncomment!' })
             -- If there is nothing after LHS then just return ''
             -- bcz the line previously (before comment) was empty
             return U.is_empty(b) and b or a .. b .. (c or '')
@@ -359,4 +361,12 @@ function U.is_commented(left, right, padding, scol, ecol)
     end
 end
 
+---Error handler
+---@param ... unknown
+function U.catch(fn, ...)
+    xpcall(fn, function(err)
+        vim.notify(string.format('[Comment] %s', err.msg), vim.log.levels.WARN)
+    end, ...)
+end
+
 return U