Trans.nvim/lua/Trans/core/translate.lua

128 lines
3.5 KiB
Lua

local Trans = require('Trans')
local util = Trans.util
local function init_opts(opts)
opts = opts or {}
opts.mode = opts.mode or ({
n = 'normal',
v = 'visual',
})[vim.api.nvim_get_mode().mode]
opts.str = util.get_str(opts.mode)
return opts
end
local function do_query(data, backend)
-- TODO : template method for online query
local name = backend.name
local uri = backend.uti
local method = backend.method
local formatter = backend.formatter
local query = backend.get_query(data)
local header
if backend.header then
if type(backend.header) == "function" then
header = backend.header(data)
else
header = backend.header
end
end
local function handle(output)
local status, body = pcall(vim.json.decode, output.body)
-- -- vim.print(body)
if not status or not body or body.errorCode ~= "0" then
if not Trans.conf.debug then backend.debug(body) end
data.result[name] = false
data[#data + 1] = output
return
end
-- check_untracked_field(body)
-- if not body.isWord then
-- data.result.youdao = {
-- title = body.query,
-- [data.from == 'en' and 'translation' or 'definition'] = body.translation,
-- }
-- return
-- end
-- local tmp = {
-- title = {
-- word = body.query,
-- phonetic = body.basic.phonetic,
-- },
-- web = body.web,
-- explains = body.basic.explains,
-- -- phrases = body.phrases,
-- -- synonyms = body.synonyms,
-- -- sentenceSample = body.sentenceSample,
-- [data.from == 'en' and 'translation' or 'definition'] = body.translation,
-- }
data.result[name] = formatter and formatter(output) or output
end
Trans.curl[method](uri, {
query = query,
callback = handle,
header = header,
})
-- Hook ?
end
---@type table<string, fun(data: TransData): true | nil>
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
---@cast backend TransBackend
backend.query(data)
local name = backend.name
while result[name] == nil do
if not update() then return end
end
if result[name] then return true end
end
end,
--- TODO :More Strategys
}
-- HACK : Core process logic
local function process(opts)
opts = init_opts(opts)
local str = opts.str
if not str or str == '' then return end
-- Find in cache
if Trans.cache[str] then
local data = Trans.cache[str]
data.frontend:process(data)
return
end
local data = Trans.data.new(opts)
if strategy[Trans.conf.query](data) then
Trans.cache[data.str] = data
data.frontend:process(data)
else
data.frontend:fallback()
end
end
---@class Trans
---@field translate fun(opts: { frontend: string?, mode: string?}?) Translate string core function
return function(opts)
coroutine.wrap(process)(opts)
end