feat: add online query support

This commit is contained in:
JuanZoran 2023-01-30 20:09:57 +08:00
parent d95bb8c8e5
commit 2377dbc0a7
9 changed files with 272 additions and 133 deletions

@ -199,13 +199,8 @@ require'Trans'.setup {
width = 37,
height = 27,
border = 'rounded',
title = {
{ '', 'TransTitleRound' },
{ ' Trans', 'TransTitle' },
{ '', 'TransTitleRound' },
},
title = title,
keymap = {
-- TODO :
pageup = '[[',
pagedown = ']]',
pin = '<leader>[',
@ -226,16 +221,13 @@ require'Trans'.setup {
'BufLeave',
},
auto_play = true,
timeout = 3000,
},
float = {
width = 0.8,
height = 0.8,
border = 'rounded',
title = {
{ '', 'TransTitleRound' },
{ ' Trans', 'TransTitle' },
{ '', 'TransTitleRound' },
},
title = title,
keymap = {
quit = 'q',
},
@ -271,17 +263,28 @@ require'Trans'.setup {
-- yes = '✔️',
-- no = '❌'
},
theme = 'default', -- 目前可选的: default, tokyonight, dracula
theme = 'default',
-- theme = 'dracula',
-- theme = 'tokyonight',
db_path = '$HOME/.vim/dict/ultimate.db',
-- TODO add online translate engine
-- online_search = {
-- enable = false,
-- engine = {},
engine = {
-- 目前支持hover窗口支持百度, 默认不开启
-- baidu = {
-- appid = '',
-- appPasswd = '',
-- },
},
-- TODO :
-- register word
-- history = {
-- -- TOOD
-- }
-- TODO register word
}
-- TODO :add online translate engine
}
```
## 快捷键绑定
@ -342,6 +345,7 @@ vim.keymap.set('n', 'mi', '<Cmd>TranslateInput<CR>')
},
}
```
## 声明
- 本插件词典基于[ECDICT](https://github.com/skywind3000/ECDICT)

@ -15,6 +15,7 @@ local content = {
if not self.modifiable then
error('content can not add newline now')
end
self.size = self.size + 1
self.lines[self.size] = value
end,
@ -23,6 +24,7 @@ local content = {
if not self.modifiable then
error('content can not add newline now')
end
self.hl_size = self.hl_size + 1
self.highlights[self.hl_size] = opt
end,
@ -32,6 +34,7 @@ local content = {
clear(self.lines)
clear(self.highlights)
self.size = 0
self.hl_size = 0
end,
---将内容连接上对应的窗口
@ -42,6 +45,7 @@ local content = {
return
end
offset = offset or 0
self.window:bufset('modifiable', true)
local window = self.window
--- NOTE : 使用-1 则需要按顺序设置
@ -71,7 +75,6 @@ local content = {
end
end,
format = function(self, ...)
local nodes = { ... }
local size = #nodes
@ -85,10 +88,7 @@ local content = {
end
local space = math.floor(((self.window.width - width) / (size - 1)))
if space > 0 then
return
end
assert(space > 0, 'try to expand the window')
local interval = (' '):rep(space)
return setmetatable({
text = table.concat(strs, interval),

@ -88,11 +88,11 @@ M.conf = {
db_path = '$HOME/.vim/dict/ultimate.db',
engine = {
baidu = {
appid = '',
appPasswd = '',
},
-- youdao = {
-- baidu = {
-- appid = '',
-- appPasswd = '',
-- },
-- -- youdao = {
-- appkey = '',
-- appPasswd = '',
-- },

@ -1,17 +1,14 @@
local baidu = require('Trans').conf.engine.baidu
local appid = baidu.appid
local appPasswd = baidu.appPasswd
local salt = tostring(math.random(bit.rshift(1, 5)))
local salt = tostring(math.random(bit.lshift(1, 15)))
local uri = 'https://fanyi-api.baidu.com/api/trans/vip/translate'
if appid == '' or appPasswd == '' then
error('请查看README, 实现在线翻译或者设置将在线翻译设置为false')
end
local ok, curl = pcall(require, 'plenary.curl')
if not ok then
error('plenary not found')
end
local post = require('Trans.util.curl').POST
local function get_field(word)
local to = 'zh'
@ -28,22 +25,40 @@ local function get_field(word)
}
end
--- this is a nice plugin
---返回一个channel
---@param word string
---@return function
return function(word)
local query = get_field(word)
local output = curl.post(uri, {
local result
post(uri, {
data = query,
headers = {
content_type = "application/x-www-form-urlencoded",
}
},
callback = function(str)
if result then
return
elseif str ~= '' then
local res = vim.fn.json_decode(str)
if res and res.trans_result then
result = {
word = word,
translation = res.trans_result[1].dst,
}
else
result = false
end
else
result = false
end
end,
})
if output.exit == 0 and output.status == 200 then
local res = vim.fn.json_decode(output.body)
if res and res.trans_result then
return {
word = word,
translation = res.trans_result[1].dst,
}
end
return function()
return result
end
end

@ -42,7 +42,7 @@ local function translate(mode, view)
mode = mode or vim.api.nvim_get_mode().mode
view = view or require('Trans').conf.view[mode]
assert(mode and view)
local word = get_word(mode)
local word = get_word(mode):gsub('^%s+', '', 1)
require('Trans.view.' .. view)(word)
end

61
lua/Trans/util/curl.lua Normal file

@ -0,0 +1,61 @@
--- TODO :wrapper for curl
local curl = {}
-- local example = {
-- data = {},
-- headers = {
-- k = 'v',
-- },
-- callback = function(output)
-- end,
-- }
curl.GET = function(uri, opts)
--- TODO :
end
curl.POST = function(uri, opts)
vim.validate {
uri = { uri, 's' },
opts = { opts, 't' }
}
local cmd = { 'curl', '-s', uri }
local size = 3
local function insert(...)
for _, v in ipairs { ... } do
size = size + 1
cmd[size] = v
end
end
local s = '"%s=%s"'
if opts.headers then
for k, v in pairs(opts.headers) do
insert('-H', s:format(k, v))
end
end
for k, v in pairs(opts.data) do
insert('-d', s:format(k, v))
end
local option
if opts.callback then
option = {
on_stdout = function (_, output)
opts.callback(table.concat(output))
end,
}
end
vim.fn.jobstart(table.concat(cmd, ' '), option)
end
return curl

@ -72,18 +72,18 @@ return function(word)
m_result = require('Trans.query.' .. engine_us)(word)
local opt = {
relative = 'editor',
width = float.width,
height = float.height,
border = float.border,
title = float.title,
row = bit.rshift((vim.o.lines - float.height), 1),
col = bit.rshift((vim.o.columns - float.width), 1),
zindex = 50,
relative = 'editor',
width = float.width,
height = float.height,
border = float.border,
title = float.title,
animation = float.animation,
row = bit.rshift((vim.o.lines - float.height), 1),
col = bit.rshift((vim.o.columns - float.width), 1),
zindex = 50,
}
m_window = require('Trans.window')(true, opt)
m_window.animation = float.animation
set_title()
m_content = m_window.contents[2]
@ -95,7 +95,6 @@ return function(word)
set_tag_hl(engine_us, 'fail')
end
m_window:draw()
m_window:open()
m_window:bufset('bufhidden', 'wipe')

@ -1,5 +1,6 @@
local api = vim.api
local conf = require('Trans').conf
local new_window = require('Trans.window')
local m_window
local m_result
@ -41,7 +42,6 @@ local process = {
it(m_result.collins and icon.star:rep(m_result.collins) or icon.notfound, 'TransCollins'),
it(m_result.oxford == 1 and icon.yes or icon.no)
)
end
m_content:addline(line)
end,
@ -166,14 +166,6 @@ local process = {
m_content:newline('')
end
end,
failed = function()
m_content:addline(
it(conf.icon.notfound .. m_indent .. '没有找到相关的翻译', 'TransFailed')
)
m_window:set_width(m_content.lines[1]:width())
end,
}
@ -264,64 +256,134 @@ action = {
end,
}
local function handle()
local hover = conf.hover
if hover.auto_play then
local ok = pcall(action.play)
if not ok then
vim.notify('自动发音失败, 请检查README发音部分', vim.log.WARN)
end
end
for _, field in ipairs(conf.order) do
process[field]()
end
for act, key in pairs(hover.keymap) do
vim.keymap.set('n', key, action[act], { buffer = true, silent = true })
end
end
local function online_query(word)
-- TODO :Progress Bar
local wait = {}
local size = 0
for k, _ in pairs(conf.engine) do
size = size + 1
wait[size] = require('Trans.query.' .. k)(word)
end
local error_msg = conf.icon.notfound .. ' 没有找到相关的翻译'
m_window:set_height(1)
local width = m_window.width
m_window:set_width(error_msg:width())
if size == 0 then
m_content:addline(it(error_msg, 'TransFailed'))
m_window:open()
return
end
m_window:open()
local timeout = conf.hover.timeout
local interval = math.floor(timeout / m_window.width)
-- --- char: ■ | □ | ▇ | ▏ ▎ ▍ ▌ ▋ ▊ ▉ █
-- --- ◖■■■■■■■◗▫◻ ▆ ▆ ▇⃞ ▉⃞
local cell = ''
local i = 1
local do_progress
do_progress = function()
m_content:wipe()
for j = 1, size do
local res = wait[j]()
if res then
m_result = res
m_window:set_width(width)
handle()
m_content:attach()
-- TODO :Animation
m_window.height = m_content:actual_height(true)
m_window:open {
animation = 'fold',
}
return
elseif res == false then
table.remove(wait, j)
size = size - 1
end
end
if i == m_window.width or size == 0 then
--- HACK : change framework
m_content:addline(
it(error_msg, 'TransFailed')
)
m_content:attach()
else
m_content:addline(
it(cell:rep(i), 'MoreMsg')
)
i = i + 1
m_content:attach()
vim.defer_fn(do_progress, interval)
end
end
do_progress()
end
return function(word)
vim.validate {
word = { word, 's' },
}
m_result = require('Trans.query.offline')(word)
local hover = conf.hover
m_window = require("Trans.window")(false, {
relative = 'cursor',
width = hover.width,
height = hover.height,
title = hover.title,
border = hover.border,
col = 1,
row = 1,
m_window = new_window(false, {
relative = 'cursor',
width = hover.width,
height = hover.height,
title = hover.title,
border = hover.border,
animation = hover.animation,
col = 1,
row = 1,
})
m_window.animation = hover.animation
m_content = m_window.contents[1]
m_result = require('Trans.query.offline')(word)
if m_result then
handle()
m_window:open({
callback = function()
m_window:set('wrap', true)
end,
})
-- TODO :Progress Bar
if not m_result then
m_result = require('Trans.query.baidu')(word)
end
if m_result and m_result.translation then
if hover.auto_play then
local ok = pcall(action.play)
if not ok then
vim.notify('自动发音失败, 请检查README发音部分', vim.log.WARN)
end
end
for _, field in ipairs(conf.order) do
process[field]()
end
for act, key in pairs(hover.keymap) do
vim.keymap.set('n', key, action[act], { buffer = true, silent = true })
local height = m_content:actual_height(true)
if height < m_window.height then
m_window:set_height(height)
end
else
process.failed()
online_query(word)
end
m_window:draw()
local height = m_content:actual_height(true)
if height < m_window.height then
m_window:set_height(height)
end
m_window:open(function()
m_window:set('wrap', true)
end)
-- Auto Close
if hover.auto_close_events then
cmd_id = api.nvim_create_autocmd(

@ -60,10 +60,7 @@ local window = {
end)
end,
---**第一次**绘制窗口的内容
---@param self table 窗口的对象
draw = function(self)
-- TODO :
local offset = 0
for _, content in ipairs(self.contents) do
content:attach(offset)
@ -71,9 +68,13 @@ local window = {
end
end,
open = function(self, callback)
local animation = self.animation
if animation.open then
open = function(self, opts)
self:draw()
opts = opts or {}
local interval = self.animation.interval
local animation = opts.animation or self.animation.open
if animation then
check_busy()
local handler
@ -85,12 +86,12 @@ local window = {
busy = true
count = count + 1
api[action](self.winid, count)
vim.defer_fn(handler[name], animation.interval)
vim.defer_fn(handler[name], interval)
else
busy = false
if callback then
callback()
if opts.callback then
opts.callback()
end
end
end
@ -101,7 +102,7 @@ local window = {
fold = wrap('fold', 'height'),
}
handler[animation.open]()
handler[animation]()
end
end,
@ -191,22 +192,19 @@ return function(entry, option)
}
local opt = {
relative = nil,
width = nil,
height = nil,
border = nil,
title = nil,
col = nil,
row = nil,
relative = option.relative,
width = option.width,
height = option.height,
border = option.border,
title = option.title,
col = option.col,
row = option.row,
title_pos = nil,
focusable = false,
zindex = 100,
zindex = option.zindex or 100,
style = 'minimal',
}
for k, v in pairs(option) do
opt[k] = v
end
if opt.title then
opt.title_pos = 'center'
end
@ -219,12 +217,13 @@ return function(entry, option)
local win
win = {
winid = winid,
bufnr = bufnr,
width = opt.width,
height = opt.height,
hl = api.nvim_create_namespace('TransWinHl'),
contents = setmetatable({}, {
winid = winid,
bufnr = bufnr,
width = opt.width,
height = opt.height,
animation = option.animation,
hl = api.nvim_create_namespace('TransWinHl'),
contents = setmetatable({}, {
__index = function(self, key)
assert(type(key) == 'number')
self[key] = require('Trans.content')(win)
@ -234,7 +233,6 @@ return function(entry, option)
}
setmetatable(win, { __index = window })
-- FIXME :config this
win:bufset('filetype', 'Trans')
win:bufset('buftype', 'nofile')