From e6e75f5e9268e33a0609c80d5fc0933a6605ee2b Mon Sep 17 00:00:00 2001
From: Shadman <13149513+shadmansaleh@users.noreply.github.com>
Date: Mon, 31 Jan 2022 17:34:53 +0000
Subject: [PATCH] fix: lualine crashing because of keyboard interrupt. (#534)

* fix: lualine crashing because of keyboard interrupt.

If keyboard interrupt occurs while lualine is evaluating statusline
lualine crashes completely. Since keyboard interrupt isn't something
we can handle try to mitigate the issue by retrying to evaluate the
statusline on error.Now lualine will retry 3 times before giving
up on an runtime error.

* Make last retry unprotected call
---
 lua/lualine.lua             |  4 ++--
 lua/lualine/utils/utils.lua | 27 +++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/lua/lualine.lua b/lua/lualine.lua
index 0ecd81d..a58a2d7 100644
--- a/lua/lualine.lua
+++ b/lua/lualine.lua
@@ -141,7 +141,7 @@ end
 ---      component objects
 ---@param is_focused boolean : whether being evsluated for focused window or not
 ---@return string statusline string
-local function statusline(sections, is_focused)
+local statusline = modules.utils.retry_call_wrap(function(sections, is_focused)
   -- The sequence sections should maintain [SECTION_SEQUENCE]
   local section_sequence = { 'a', 'b', 'c', 'x', 'y', 'z' }
   local status = {}
@@ -173,7 +173,7 @@ local function statusline(sections, is_focused)
     table.insert(status, modules.highlight.format_highlight('lualine_c') .. '%=')
   end
   return apply_transitional_separators(table.concat(status))
-end
+end)
 
 --- check if any extension matches the filetype and return proper sections
 ---@param current_ft string : filetype name of current file
diff --git a/lua/lualine/utils/utils.lua b/lua/lualine/utils/utils.lua
index eeea03d..17dcea4 100644
--- a/lua/lualine/utils/utils.lua
+++ b/lua/lualine/utils/utils.lua
@@ -143,4 +143,31 @@ function M.is_component(comp)
   return mt and mt.__is_lualine_component == true
 end
 
+--- Call function with args and return it's result.
+--- If error occurs during fn retry times times.
+---@param fn function Function to call.
+---@param args table List of arguments used for calling function.
+---@param times number Number of times to retry on error.
+---@return any Result of fn.
+function M.retry_call(fn, args, times)
+  times = times or 3
+  for _=0,times-1 do
+    local result = {pcall(fn, unpack(args))}
+    if result[1] == true then
+      return unpack(result, 2)
+    end
+  end
+  return fn(unpack(args))
+end
+
+--- Wrap a function in retry_call
+---@param fn function Function to call.
+---@param times number Number of times to retry on error.
+---@return function retry call wraped function
+function M.retry_call_wrap(fn, times)
+  return function(...)
+    return M.retry_call(fn, {...}, times)
+  end
+end
+
 return M