From f17171d28baaa1b0ce643f54ab619b7bdc340342 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Sat, 6 May 2023 11:38:37 +0800
Subject: [PATCH] fix: query strategy

---
 lua/Trans/backend/offline.lua        |  3 +-
 lua/Trans/core/backend.lua           | 57 ++++++++++++++++---
 lua/Trans/core/data.lua              |  2 +-
 lua/Trans/core/frontend.lua          |  1 -
 lua/Trans/core/translate.lua         | 82 +++-------------------------
 lua/Trans/frontend/hover/execute.lua | 14 ++++-
 lua/Trans/frontend/hover/init.lua    | 17 ++++--
 lua/Trans/init.lua                   |  2 +
 lua/Trans/strategy/fallback.lua      | 27 +++++++++
 lua/Trans/style/spinner.lua          |  8 ---
 10 files changed, 110 insertions(+), 103 deletions(-)
 create mode 100644 lua/Trans/strategy/fallback.lua

diff --git a/lua/Trans/backend/offline.lua b/lua/Trans/backend/offline.lua
index 2ef618e..e3e259e 100644
--- a/lua/Trans/backend/offline.lua
+++ b/lua/Trans/backend/offline.lua
@@ -18,8 +18,6 @@ local M = {
 }
 
 ---@param data any
----@return any
----@overload fun(TransData): TransResult
 function M.query(data)
     if data.is_word == false or data.from == 'zh' then
         return
@@ -34,6 +32,7 @@ function M.query(data)
     data.result.offline = res and M.formatter(res) or false
 end
 
+
 -- this is a awesome plugin
 M.query_field = {
     'word',
diff --git a/lua/Trans/core/backend.lua b/lua/Trans/core/backend.lua
index e11f8fe..8ba6a1d 100644
--- a/lua/Trans/core/backend.lua
+++ b/lua/Trans/core/backend.lua
@@ -1,9 +1,7 @@
 local Trans = require 'Trans'
 
-
 ---@class TransBackend
 ---@field no_wait? boolean whether need to wait for the result
----@field all_name string[] @all backend name
 ---@field name string @backend name
 ---@field name_zh string @backend name in Chinese
 
@@ -15,6 +13,9 @@ local Trans = require 'Trans'
 ---@field header? table<string, string> | fun(data: TransData): table<string, string> @request header
 ---@field debug? fun(body: table?) @debug
 
+---@class TransOfflineBackend: TransBackend
+---@field query fun(data: TransData)
+---@field query_field string[] @query field
 
 local conf = Trans.conf
 --- INFO :Parse online engine keys config file
@@ -29,8 +30,10 @@ if file then
     file:close()
 end
 
+local all_name = {
+    'offline', -- default backend
+}
 
-local all_name = {}
 for _, config in ipairs(user_conf) do
     if not config.disable then
         all_name[#all_name + 1] = config.name
@@ -38,21 +41,57 @@ for _, config in ipairs(user_conf) do
     end
 end
 
-
 ---@class TransBackends
 ---@field all_name string[] all backend names
+local M = {
+    all_name = all_name,
+}
+
+---Template method for online query
+---@param data TransData @data
+---@param backend TransOnlineBackend @backend
+function M.do_query(data, backend)
+    local name      = backend.name
+    local uri       = backend.uri
+    local method    = backend.method
+    local formatter = backend.formatter
+    local query     = backend.get_query(data)
+    local header    = type(backend.header) == 'function' and backend.header(data) or backend.header
+
+    local function handle(output)
+        local status, body = pcall(vim.json.decode, output.body)
+        if not status or not body then
+            if not Trans.conf.debug then
+                backend.debug(body)
+                data.trace[name] = output
+            end
+
+            data.result[name] = false
+            return
+        end
+
+        data.result[name] = formatter(body, data)
+    end
+
+    Trans.curl[method](uri, {
+        query = query,
+        callback = handle,
+        header = header,
+    })
+    -- Hook ?
+end
 
 ---@class Trans
 ---@field backend TransBackends
-return setmetatable({
-    all_name = all_name,
-}, {
+return setmetatable(M, {
     __index = function(self, name)
         ---@type TransBackend
         local backend = require('Trans.backend.' .. name)
 
-        for key, value in pairs(user_conf[name] or {}) do
-            backend[key] = value
+        if user_conf[name] then
+            for key, value in pairs(user_conf[name]) do
+                backend[key] = value
+            end
         end
 
         self[name] = backend
diff --git a/lua/Trans/core/data.lua b/lua/Trans/core/data.lua
index d911534..b5d0cec 100644
--- a/lua/Trans/core/data.lua
+++ b/lua/Trans/core/data.lua
@@ -10,7 +10,7 @@ local Trans = require 'Trans'
 ---@field result table<string, TransResult|nil|false> @The result of the translation
 ---@field frontend TransFrontend
 ---@field trace table<string, string> debug message
----@field backends table<string, TransBackend>
+---@field backends TransBackend[]
 local M = {}
 M.__index = M
 
diff --git a/lua/Trans/core/frontend.lua b/lua/Trans/core/frontend.lua
index 351e4d1..5cd05d1 100644
--- a/lua/Trans/core/frontend.lua
+++ b/lua/Trans/core/frontend.lua
@@ -1,7 +1,6 @@
 local Trans         = require 'Trans'
 local frontend_opts = Trans.conf.frontend
 
-
 ---@class TransFrontend
 ---@field opts TransFrontendOpts
 ---@field get_active_instance fun():TransFrontend?
diff --git a/lua/Trans/core/translate.lua b/lua/Trans/core/translate.lua
index f9263ce..244426a 100644
--- a/lua/Trans/core/translate.lua
+++ b/lua/Trans/core/translate.lua
@@ -1,80 +1,12 @@
 local Trans = require 'Trans'
-local util = Trans.util
-
-local function init_opts(opts)
-    opts = opts or {}
-    opts.mode = opts.mode or vim.fn.mode()
-    opts.str = util.get_str(opts.mode)
-    return opts
-end
-
-
----To Do Online Query
----@param data TransData @data
----@param backend TransOnlineBackend @backend
-local function do_query(data, backend)
-    -- TODO : template method for online query
-    local name      = backend.name
-    local uri       = backend.uri
-    local method    = backend.method
-    local formatter = backend.formatter
-    local query     = backend.get_query(data)
-    local header    = type(backend.header) == 'function' and backend.header(data) or backend.header
-
-    local function handle(output)
-        local status, body = pcall(vim.json.decode, output.body)
-        if not status or not body then
-            if not Trans.conf.debug then
-                backend.debug(body)
-                data.trace[name] = output
-            end
-
-            data.result[name] = false
-            return
-        end
-
-        -- vim.print(data.result[name])
-        data.result[name] = formatter(body, data)
-    end
-
-    Trans.curl[method](uri, {
-        query = query,
-        callback = handle,
-        header = header,
-    })
-    -- Hook ?
-end
-
----@type table<string, fun(data: TransData):boolean>
-local strategy = {
-    fallback = function(data)
-        local result = data.result
-        Trans.backend.offline.query(data)
-
-        if result.offline then return true end
-
-        local update = data.frontend:wait()
-        for _, backend in ipairs(data.backends) do
-            do_query(data, backend)
-
-            local name = backend.name
-            ---@cast backend TransBackend
-            while result[name] == nil and update(backend) do
-            end
-
-            if result[name] then return true end
-        end
-
-        return false
-    end,
-    --- TODO :More Strategys
-}
-
 
 -- HACK : Core process logic
 local function process(opts)
-    opts = init_opts(opts)
-    local str = opts.str
+    opts = opts or {}
+    opts.mode = opts.mode or vim.fn.mode()
+    local str = Trans.util.get_str(opts.mode)
+    opts.str = str
+
     if not str or str == '' then return end
 
 
@@ -86,7 +18,7 @@ local function process(opts)
     end
 
     local data = Trans.data.new(opts)
-    if strategy[data.frontend.opts.query](data) then
+    if Trans.strategy[data.frontend.opts.query](data) then
         Trans.cache[data.str] = data
         data.frontend:process(data)
     else
@@ -94,9 +26,9 @@ local function process(opts)
     end
 end
 
-
 ---@class Trans
 ---@field translate fun(opts: { frontend: string?, mode: string?}?) Translate string core function
+
 return function(opts)
     coroutine.wrap(process)(opts)
 end
diff --git a/lua/Trans/frontend/hover/execute.lua b/lua/Trans/frontend/hover/execute.lua
index 651893e..75b7e87 100644
--- a/lua/Trans/frontend/hover/execute.lua
+++ b/lua/Trans/frontend/hover/execute.lua
@@ -5,9 +5,11 @@ local strategy = {
     pageup = function(hover)
         hover.buffer:normal 'gg'
     end,
+
     pagedown = function(hover)
         hover.buffer:normal 'G'
     end,
+
     pin = function(hover)
         if hover.pin then
             return
@@ -27,9 +29,11 @@ local strategy = {
 
         window:set('wrap', true)
     end,
+
     close = function(hover)
         hover:destroy()
     end,
+
     toggle_entry = function(hover)
         if api.nvim_get_current_win() ~= hover.window.winid then
             api.nvim_set_current_win(hover.window.winid)
@@ -48,6 +52,12 @@ local strategy = {
 ---@class TransHover
 ---@field execute fun(hover: TransHover, action: string)
 return function(hover, action)
-    -- TODO :
-    strategy[action](hover)
+    return strategy[action](hover)
 end
+
+-- This function will be called within coroutine, so we can't use __call
+-- return setmetatable(strategy, {
+--     __call = function(_, hover, action)
+--         return strategy[action](hover)
+--     end,
+-- })
diff --git a/lua/Trans/frontend/hover/init.lua b/lua/Trans/frontend/hover/init.lua
index 05e3711..9e477ef 100644
--- a/lua/Trans/frontend/hover/init.lua
+++ b/lua/Trans/frontend/hover/init.lua
@@ -19,7 +19,11 @@ local M = Trans.metatable('frontend.hover', {
 M.__index = M
 
 
----Set up function which will be invoked when this module is loaded
+--[[
+Set up function which will be invoked when this module is loaded
+
+Because the options are not loaded yet when this module is loaded
+--]]
 function M.setup()
     local set = vim.keymap.set
     for action, key in pairs(M.opts.keymaps) do
@@ -89,15 +93,18 @@ end
 function M:init_window(opts)
     opts = opts or {}
     local m_opts = self.opts
+
+
+    ---@format disable-next
     local option = {
         buffer = self.buffer,
         animation = m_opts.animation,
         win_opts = {
             relative  = opts.relative or 'cursor',
-            col       = opts.col or 1,
-            row       = opts.row or 1,
-            width     = opts.width or m_opts.width,
-            height    = opts.height or m_opts.height,
+            col       = opts.col      or 1,
+            row       = opts.row      or 1,
+            width     = opts.width    or m_opts.width,
+            height    = opts.height   or m_opts.height,
             title     = m_opts.title,
             title_pos = m_opts.title and 'center',
             zindex    = 100,
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index b592e08..c4df2c8 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -32,9 +32,11 @@ local sep = system == 'win' and '\\\\' or '/'
 ---@field plugin_dir string @Plugin directory
 ---@field separator string @Path separator
 ---@field system 'mac'|'win'|'termux'|'linux' @Path separator
+---@field strategy table<string, fun(data: TransData):boolean> Translate string core function
 local M = metatable('core', {
     cache      = {},
     style      = metatable 'style',
+    strategy   = metatable 'strategy',
     separator  = sep,
     system     = system,
     plugin_dir = debug.getinfo(1, 'S').source:sub(2):match('(.-)lua' .. sep .. 'Trans'),
diff --git a/lua/Trans/strategy/fallback.lua b/lua/Trans/strategy/fallback.lua
new file mode 100644
index 0000000..7d05a3b
--- /dev/null
+++ b/lua/Trans/strategy/fallback.lua
@@ -0,0 +1,27 @@
+---Fallback query strategy
+---@param data TransData
+---@return boolean @true if query success
+return function(data)
+    local result = data.result
+    local update
+    for _, backend in ipairs(data.backends) do
+        local name = backend.name
+
+        if backend.no_wait then
+            ---@cast backend TransOfflineBackend
+            backend.query(data)
+        else
+            ---@cast backend TransOnlineBackend
+            require 'Trans'.backend.do_query(data, backend)
+            update = update or data.frontend:wait()
+
+            while result[name] == nil and update(backend) do
+            end
+        end
+
+        ---@cast backend TransBackend
+        if result[name] then return true end
+    end
+
+    return false
+end
diff --git a/lua/Trans/style/spinner.lua b/lua/Trans/style/spinner.lua
index a3e3461..fbbaba5 100644
--- a/lua/Trans/style/spinner.lua
+++ b/lua/Trans/style/spinner.lua
@@ -393,14 +393,6 @@ return {
         '◉',
         '◎'
     },
-    star = {
-        '✶',
-        '✸',
-        '✹',
-        '✺',
-        '✹',
-        '✷'
-    },
     star2 = {
         '+',
         'x',