From 21a100b6c7847aa21b7933eb307b007d5d476184 Mon Sep 17 00:00:00 2001 From: JuanZoran <1430359574@qq.com> Date: Mon, 10 Jul 2023 21:19:55 +0800 Subject: [PATCH] chore: backup progress, begin to rewrite version 3 --- lua/Trans/backend/baidu.lua | 43 +++++-- lua/Trans/backend/offline.lua | 192 +++++++++++++++++++++++++++++- lua/Trans/core/backend.lua | 213 ++++++++++++++++++++++------------ lua/Trans/core/loader.lua | 6 + lua/Trans/core/window.lua | 15 +-- lua/Trans/init.lua | 6 +- 6 files changed, 379 insertions(+), 96 deletions(-) create mode 100644 lua/Trans/core/loader.lua diff --git a/lua/Trans/backend/baidu.lua b/lua/Trans/backend/baidu.lua index e01600e..3980b21 100644 --- a/lua/Trans/backend/baidu.lua +++ b/lua/Trans/backend/baidu.lua @@ -12,7 +12,6 @@ local M = { method = 'get', } - local Trans = require 'Trans' ---@class BaiduQuery @@ -26,7 +25,7 @@ local Trans = require 'Trans' ---Get content for query ---@param data TransData ---@return BaiduQuery -function M.get_query(data) +local function get_query(data) local tmp = M.app_id .. data.str .. M.salt .. M.app_passwd local sign = Trans.util.md5.sumhexa(tmp) @@ -40,11 +39,12 @@ function M.get_query(data) } end + ---@overload fun(body: table, data:TransData): TransResult ---Query Using Baidu API ---@param body table BaiduQuery Response ---@return table|false -function M.formatter(body, data) +local function formatter(body, data) local result = body.trans_result if not result then return false end @@ -57,14 +57,41 @@ function M.formatter(body, data) } end ----@class TransBackend + +---@class TransBackendCore ---@field baidu Baidu -return M +return { + name = 'baidu', + display_text = '百度', + uri = 'https://fanyi-api.baidu.com/api/trans/vip/translate', + method = 'get', + get_query = get_query, + formatter = formatter, +} + + + + + + + + + + + + + + + + + + + --- -- NOTE :free tts: --- -- https://zj.v.api.aa1.cn/api/baidu-01/?msg=我爱你&choose=0&su=100&yd=5 --- -- 选择转音频的人物,女生1 输入0 | 女生2输入:5|男生1 输入:1|男生2 输入:2|男生3 输入:3 +-- NOTE :free tts: +-- https://zj.v.api.aa1.cn/api/baidu-01/?msg=我爱你&choose=0&su=100&yd=5 +-- 选择转音频的人物,女生1 输入0 | 女生2输入:5|男生1 输入:1|男生2 输入:2|男生3 输入:3 -- { -- body = '{"from":"en","to":"zh","trans_result":[{"src":"require","dst":"\\u8981\\u6c42"}]}', -- exit = 0, diff --git a/lua/Trans/backend/offline.lua b/lua/Trans/backend/offline.lua index e3e259e..79ce48c 100644 --- a/lua/Trans/backend/offline.lua +++ b/lua/Trans/backend/offline.lua @@ -1,4 +1,191 @@ -local Trans = require 'Trans' +local Trans = require 'Trans' +if false then + -- local dict = db:open(Trans.conf.dir .. Trans.separator .. 'ultimate.db') + local db = require 'sqlite.db' + local conf = Trans.loader.conf + local dict = db:open(conf.dict) + vim.api.nvim_create_autocmd('VimLeavePre', { + callback = function() + if db:isopen() then db:close() end + end, + }) + + ---@class TransOfflineBackend + local M = { + name = 'offline', + name_zh = '本地', + no_wait = true, + } + + ---@param data any + function M.query(data) + if data.is_word == false or data.from == 'zh' then + return + end + + local res = dict:select(conf.db_name, { + where = { word = data.str }, + keys = M.query_field, + limit = 1, + })[1] + + data.result.offline = res and M.formatter(res) or false + end + + -- this is a awesome plugin + M.query_field = { + 'word', + 'phonetic', + 'definition', + 'translation', + 'pos', + 'collins', + 'oxford', + 'tag', + 'exchange', + } + + local function exist(str) + return str and str ~= '' + end + + ---@type (fun(res):any)[] + local formatter = { + title = function(res) + local title = { + word = res.word, + oxford = res.oxford, + collins = res.collins, + phonetic = res.phonetic, + } + + res.word = nil + res.oxford = nil + res.collins = nil + res.phonetic = nil + return title + end, + tag = function(res) + if not exist(res.tag) then + return + end + local tag_map = { + zk = '中考', + gk = '高考', + ky = '考研', + gre = 'gre ', + cet4 = '四级', + cet6 = '六级', + ielts = '雅思', + toefl = '托福', + } + + local tag = {} + for i, _tag in ipairs(vim.split(res.tag, ' ', { plain = true })) do + tag[i] = tag_map[_tag] + end + + return tag + end, + exchange = function(res) + if not exist(res.exchange) then + return + end + local exchange_map = { + ['0'] = '原型 ', + ['1'] = '类别 ', + ['p'] = '过去式 ', + ['r'] = '比较级 ', + ['t'] = '最高级 ', + ['b'] = '比较级 ', + ['z'] = '最高级 ', + ['s'] = '复数 ', + ['d'] = '过去分词 ', + ['i'] = '现在分词 ', + ['3'] = '第三人称单数', + ['f'] = '第三人称单数', + } + + local exchange = {} + for _, _exchange in ipairs(vim.split(res.exchange, '/', { plain = true })) do + exchange[exchange_map[_exchange:sub(1, 1)]] = _exchange:sub(3) + end + + return exchange + end, + pos = function(res) + if not exist(res.pos) then + return + end + local pos_map = { + a = '代词pron ', + c = '连接词conj ', + i = '介词prep ', + j = '形容词adj ', + m = '数词num ', + n = '名词n ', + p = '代词pron ', + r = '副词adv ', + u = '感叹词int ', + v = '动词v ', + x = '否定标记not ', + t = '不定式标记infm ', + d = '限定词determiner ', + } + + local pos = {} + for _, _pos in ipairs(vim.split(res.pos, '/', { plain = true })) do + pos[pos_map[_pos:sub(1, 1)]] = ('%2s%%'):format(_pos:sub(3)) + end + + return pos + end, + translation = function(res) + if not exist(res.translation) then + return + end + local translation = {} + for i, _translation in ipairs(vim.split(res.translation, '\n', { plain = true })) do + translation[i] = _translation + end + + return translation + end, + definition = function(res) + if not exist(res.definition) then + return + end + local definition = {} + for i, _definition in ipairs(vim.split(res.definition, '\n', { plain = true })) do + -- -- TODO :判断是否需要分割空格 + definition[i] = _definition:gsub('^%s+', '', 1) + end + + return definition + end, + } + + ---Formater for TransResul + ---@param res TransResult + ---@return TransResult + function M.formatter(res) + for field, func in pairs(formatter) do + res[field] = func(res) + end + + return res + end + + ---@class TransBackends + ---@field offline TransOfflineBackend + return { + name = 'offline', + name_zh = '本地', + no_wait = true, + } +end + + local db = require 'sqlite.db' local path = Trans.conf.dir .. Trans.separator .. 'ultimate.db' @@ -32,7 +219,6 @@ function M.query(data) data.result.offline = res and M.formatter(res) or false end - -- this is a awesome plugin M.query_field = { 'word', @@ -177,6 +363,4 @@ function M.formatter(res) return res end ----@class TransBackends ----@field offline TransOfflineBackend return M diff --git a/lua/Trans/core/backend.lua b/lua/Trans/core/backend.lua index 8ba6a1d..ab85303 100644 --- a/lua/Trans/core/backend.lua +++ b/lua/Trans/core/backend.lua @@ -2,99 +2,166 @@ local Trans = require 'Trans' ---@class TransBackend ---@field no_wait? boolean whether need to wait for the result ----@field name string @backend name ----@field name_zh string @backend name in Chinese +---@field name string +---@field display_text string? +---@field conf table? @User specific config ----@class TransOnlineBackend: TransBackend + +---@class TransBackendOnline: TransBackend ---@field uri string @request uri ---@field method 'get' | 'post' @request method ---@field formatter fun(body: table, data: TransData): TransResult|false|nil @formatter ----@field get_query fun(data: TransData): table @get query ----@field header? table | fun(data: TransData): table @request header ----@field debug? fun(body: table?) @debug +---@field get_query fun(data: TransData): table @get query table ----@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 -local path = conf.dir .. '/Trans.json' -local file = io.open(path, 'r') +---@class TransBackendOffline: TransBackend +---@field query fun(data: TransData) -local user_conf = {} -if file then - local content = file:read '*a' - user_conf = vim.json.decode(content) or user_conf - file:close() -end -local all_name = { - 'offline', -- default backend -} -for _, config in ipairs(user_conf) do - if not config.disable then - all_name[#all_name + 1] = config.name - user_conf[config.name] = config - end -end - ----@class TransBackends ----@field all_name string[] all backend names +---@class TransBackendCore local M = { - all_name = all_name, + ---@type table + sources = {}, } ----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 +local m_util = {} + + + +-- TODO :Implement all of utility functions + + +M.util = m_util +M.random_num = math.random(bit.lshift(1, 15)) + ---@class Trans ----@field backend TransBackends +---@field backend TransBackendCore return setmetatable(M, { __index = function(self, name) ---@type TransBackend local backend = require('Trans.backend.' .. name) + backend.conf = user_conf[name] - if user_conf[name] then - for key, value in pairs(user_conf[name]) do - backend[key] = value - end - end - - self[name] = backend + self.sources[name] = backend return backend end, }) + + +-- local new = (function() +-- ---@class TransBackend +-- local mt = { +-- ---State hooks +-- ---@param self TransBackend +-- ---@param state TransState @state name +-- ---@param hook fun() hook function +-- ---@param event? TransEvents +-- register = function(self, state, hook, event) +-- table.insert(self.on[state][event], hook) +-- end, + +-- ---Update state and Notify hooks +-- ---@param self TransBackend +-- ---@param newstate TransState @state name +-- update = function(self, newstate) +-- -- Enter +-- for _, hook in ipairs(self.on[newstate].enter) do +-- hook() +-- end + +-- -- Leave +-- for _, hook in ipairs(self.on[self.state].leave) do +-- hook() +-- end + +-- -- Change +-- for _, hook in ipairs(self.on[self.state].change) do +-- hook() +-- end + +-- for _, hook in ipairs(self.on[newstate].change) do +-- hook() +-- end + +-- self.state = newstate +-- end, +-- } +-- mt.__index = mt + +-- ---TransBackend Constructor +-- ---@param origin TransBackendDefinition +-- ---@return TransBackend +-- return function(origin) +-- origin.on = vim.defaulttable() +-- origin.state = origin.state or 'IDLE' +-- ---@cast origin TransBackend +-- return setmetatable(origin, mt) +-- end +-- end)() + +-- local conf = Trans.conf +-- --- INFO :Parse online engine keys config file +-- local path = conf.dir .. '/Trans.json' +-- local file = io.open(path, 'r') + + +-- local user_conf = {} +-- if file then +-- local content = file:read '*a' +-- user_conf = vim.json.decode(content) or user_conf +-- file:close() +-- end + +-- local all_name = { +-- 'offline', -- default backend +-- } + +-- for _, config in ipairs(user_conf) do +-- if not config.disable then +-- all_name[#all_name + 1] = config.name +-- user_conf[config.name] = config +-- 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 diff --git a/lua/Trans/core/loader.lua b/lua/Trans/core/loader.lua new file mode 100644 index 0000000..63c99e3 --- /dev/null +++ b/lua/Trans/core/loader.lua @@ -0,0 +1,6 @@ +local M = {} + +-- TODO : + + +return M diff --git a/lua/Trans/core/window.lua b/lua/Trans/core/window.lua index 7a3a234..815be0b 100644 --- a/lua/Trans/core/window.lua +++ b/lua/Trans/core/window.lua @@ -184,11 +184,12 @@ window.__index = window -- relative = relative, -- } +---@class TransWindowOpts local default_opts = { - enter = false, - winid = -1, + enter = false, + winid = -1, ---@type WindowOpts - win_opts = { + win_opts = { -- INFO : ensured options -- col -- row @@ -201,14 +202,10 @@ local default_opts = { focusable = true, noautocmd = true, }, + animation = nil, ---@type table? Hover Window Animation + buffer = nil, ---@type TransBuffer attached buffer object } ----@class TransWindowOpts ----@field buffer TransBuffer attached buffer object ----@field enter? boolean cursor should [enter] window when open,default: false ----@field win_opts WindowOpts window config [**When open**] ----@field animation? table? Hover Window Animation - ---Create new window ---@param opts TransWindowOpts window config ---@return TransWindow diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua index c4df2c8..b051b23 100644 --- a/lua/Trans/init.lua +++ b/lua/Trans/init.lua @@ -7,17 +7,17 @@ local function metatable(folder_name, origin) __index = function(tbl, key) local status, result = pcall(require, ('Trans.%s.%s'):format(folder_name, key)) if status then - tbl[key] = result + rawset(tbl, key, result) return result end end, }) end + ---@class string ---@field width function @Get string display width ---@field play function @Use tts to play string - local uname = vim.loop.os_uname().sysname local system = uname == 'Darwin' and 'mac' or @@ -25,6 +25,7 @@ local system = uname == 'Linux' and (vim.fn.executable 'termux-api-start' == 1 and 'termux' or 'linux') or error 'Unknown System, Please Report Issue' + local sep = system == 'win' and '\\\\' or '/' ---@class Trans ---@field style table @Style module @@ -42,6 +43,7 @@ local M = metatable('core', { plugin_dir = debug.getinfo(1, 'S').source:sub(2):match('(.-)lua' .. sep .. 'Trans'), }) + M.metatable = metatable ---Get abs_path of file