feat: add online query support
This commit is contained in:
parent
d95bb8c8e5
commit
2377dbc0a7
README.md
lua/Trans
40
README.md
40
README.md
@ -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
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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user