diff --git a/lua/Trans/conf.lua b/lua/Trans/conf.lua index 37acd42..493d001 100644 --- a/lua/Trans/conf.lua +++ b/lua/Trans/conf.lua @@ -1,17 +1,28 @@ return { + view = { + cursor = { + -- NOTE : + -- 可选的风格:['fixed', 'relative', .. ] + style = 'fixed', + border = 'rounded', + -- NOTE : + -- 如果style设置为'relative' + -- 则其值代表最大限制, 设置为负数则无限制 + width = 30, + height = 30, + }, + float = { + top_offset = 1, + relative_width = 0.8, + border = 'rounded', + }, + }, display = { - style = 'minimal', - max_height = 50, -- 小于0代表无限制 - max_width = 50, - -- phnoetic = true, + phnoetic = true, collins_star = true, oxford = true, + -- TODO -- history = false, - wrap = true, - border_style = 'rounded', - view = 'cursor', - offset_x = 2, - offset_y = 2, }, order = { 'title', @@ -22,7 +33,35 @@ return { 'en', }, - db_path = '$HOME/.vim/dict/ultimate.db', -- FIXME: change the path + highligh = { + TransWord = { + fg = '#7ee787', + bold = true, + }, + TransPhonetic = { + fg = '#8b949e', + }, + TransRef = { + fg = '#75beff', + bold = true, + }, + TransTag = { + fg = '#e5c07b', + }, + TransExchange = { + link = 'TransTag', + }, + TransPos = { + link = 'TransTag', + }, + TransZh = { + link = 'TransWord', + }, + TransEn = { + fg = '#bc8cff', + }, + }, + db_path = '$HOME/.vim/dict/ultimate.db', icon = { star = '⭐', @@ -30,13 +69,12 @@ return { notOxford = '' }, auto_close = true, - buf = vim.api.nvim_create_buf(false, true) - -- TODO: add online translate engine + -- TODO add online translate engine -- online_search = { -- enable = false, -- engine = {}, -- } - -- TODO: register word + -- TODO register word } diff --git a/lua/Trans/database.lua b/lua/Trans/database.lua index a0b0efd..a5b77c0 100644 --- a/lua/Trans/database.lua +++ b/lua/Trans/database.lua @@ -1,20 +1,6 @@ local M = {} -local db_path = require("Trans").conf.db_path -local dict = require("Trans").db:open(db_path) function M.query(arg) - -- TODO: return type: a result table: - local res = {} - if type(arg) == 'string' then - res = dict:select('stardict', { - where = { word = arg }, - }) - elseif type(arg) == 'table' then - res = dict:select('stardict', arg) - else - vim.notify('query argument error!') - end - return res[1] end return M diff --git a/lua/Trans/display.lua b/lua/Trans/display.lua index 41c1d93..2b41cca 100644 --- a/lua/Trans/display.lua +++ b/lua/Trans/display.lua @@ -1,309 +1,338 @@ -local M = {} - +---@diagnostic disable: unused-local +local M = {} local api = vim.api -local display = require("Trans").conf.display -local icon = require("Trans").conf.icon -local order = require("Trans").conf.order -local auto_close = require("Trans").conf.auto_close +local conf = require("Trans").conf +local display = conf.display +local icon = conf.icon +local order = conf.order +local auto_close = conf.auto_close +local view = conf.view -local hl = require("Trans.highlight").hlgroup +-- TODO : setup database +local db_path = require("Trans").conf.db_path +local dict = require("Trans").db:open(db_path) -local buf = require("Trans.conf").buf -local win = 0 -local line = 0 -local pos_info = {} +local highlight = { + word = 'TransWord', + phonetic = 'TransPhonetic', + ref = 'TransRef', + tag = 'TransTag', + exchange = 'TransExchange', + pos = 'TransPos', + zh = 'TransZh', + en = 'TransEn', +} -local handler = {} -api.nvim_buf_set_option(buf, 'filetype', 'Trans') - -local function show_win(width, height) - win = api.nvim_open_win(buf, false, { - relative = 'cursor', - col = display.offset_x, - row = display.offset_y, - title = 'Trans', - title_pos = 'center', - style = display.style, - width = (display.max_width > 0 and width > display.max_width) and display.max_width or width, - height = (display.max_width > 0 and height > display.max_height) and display.max_height or height, - border = display.border_style, - focusable = false, - zindex = 250, -- Top - }) - api.nvim_win_set_option(win, 'wrap', display.wrap) -end - --- NOTE title -handler.title = function(text, query_res) - local title = ('%s [%s] %s %s'):format( - query_res.word, - query_res.phonetic, - (display.oxford and (query_res.oxford == 1 and icon.isOxford or icon.notOxford) or ''), - ((display.collins_star and query_res.collins) and string.rep(icon.star, query_res.collins) or '') - ) - table.insert(text, title) - - pos_info.title = {} - pos_info.title.word = #query_res.word - pos_info.title.phonetic = query_res.phonetic and #query_res.phonetic or 3 - pos_info.title.line = line - line = line + 1 -end - --- NOTE tag -handler.tag = function(text, query_res) - if query_res.tag and #query_res.tag > 0 then - local tag = query_res.tag:gsub('zk', '中考'):gsub('gk', '高考'):gsub('ky', '考研'):gsub('cet4', '四级'): - gsub('cet6', '六级'):gsub('ielts', '雅思'):gsub('toefl', '托福'):gsub('gre', 'GRE') - - table.insert(text, '标签:') - table.insert(text, ' ' .. tag) - table.insert(text, '') - - pos_info.tag = line - line = line + 3 - end -end - --- NOTE pos 词性 -handler.pos = function(text, query_res) - if query_res.pos and #query_res.pos > 0 then - table.insert(text, '词性:') - - local content = 0 - for v in vim.gsplit(query_res.pos, [[/]]) do - table.insert(text, string.format(' %s', v .. '%')) - content = content + 1 - end - - table.insert(text, '') - - pos_info.pos = {} - pos_info.pos.line = line - pos_info.pos.content = content - line = line + content + 2 - end -end - --- NOTE exchange -handler.exchange = function(text, query_res) - if query_res.exchange and #query_res.exchange > 0 then - table.insert(text, '词形变化:') - - local exchange_map = { - p = '过去式', - d = '过去分词', - i = '现在分词', - r = '形容词比较级', - t = '形容词最高级', - s = '名词复数形式', - O = '词干', - ['3'] = '第三人称单数', - } - - local content = 0 - for v in vim.gsplit(query_res.exchange, [[/]]) do - table.insert(text, string.format(' %s: %s', exchange_map[v:sub(1, 1)], v:sub(3))) - content = content + 1 - -- FIXME: 中文字符与字母位宽不一致, 暂时无法对齐 - end - table.insert(text, '') - - pos_info.exchange = {} - pos_info.exchange.line = line - pos_info.exchange.content = content - line = line + content + 2 - end -end - --- NOTE 中文翻译 -handler.zh = function(text, query_res) - if query_res.translation then - table.insert(text, '中文翻译:') - - local content = 0 - for v in vim.gsplit(query_res.translation, '\n') do - table.insert(text, ' ' .. v) - content = content + 1 - end - table.insert(text, '') - - pos_info.zh = {} - pos_info.zh.line = line - pos_info.zh.content = content - line = content + line + 2 - end -end - --- NOTE 英文翻译 -handler.en = function(text, query_res) - if query_res.definition and #query_res.definition > 0 then - table.insert(text, '英文翻译:') - - local content = 0 - for v in vim.gsplit(query_res.definition, '\n') do - table.insert(text, ' ' .. v) - content = content + 1 - end - table.insert(text, '') - - pos_info.en = {} - pos_info.en.line = line - pos_info.en.content = content - line = line + content + 2 - end -end - --- @return string array -local function get_text(query_res) - local text = {} - for _, v in ipairs(order) do - handler[v](text, query_res) - end - return text -end - -local function set_text(query_res) - local text = query_res and get_text(query_res) or { '没有找到相关定义' } - - api.nvim_buf_set_lines(buf, 0, -1, false, text) - local width = 0 - for _, v in ipairs(text) do - if #v > width then - width = v:len() - end - end - return width, #text -end - -local hl_handler = {} - -hl_handler.title = function() - api.nvim_buf_add_highlight(buf, -1, hl.word, pos_info.title.line, 0, pos_info.title.word) - api.nvim_buf_add_highlight(buf, -1, hl.phonetic, pos_info.title.line, pos_info.title.word + 5, - pos_info.title.word + 5 + pos_info.title.phonetic) -end - -hl_handler.tag = function() - if pos_info.tag then - api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.tag, 0, -1) - api.nvim_buf_add_highlight(buf, -1, hl.tag, pos_info.tag + 1, 0, -1) - end -end - -hl_handler.pos = function() - if pos_info.pos then - api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.pos.line, 0, -1) - for i = 1, pos_info.pos.content, 1 do - api.nvim_buf_add_highlight(buf, -1, hl.pos, pos_info.pos.line + i, 0, -1) - end - end -end - -hl_handler.exchange = function() - if pos_info.exchange then - api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.exchange.line, 0, -1) - for i = 1, pos_info.exchange.content, 1 do - api.nvim_buf_add_highlight(buf, -1, hl.exchange, pos_info.exchange.line + i, 0, -1) - end - end -end - -hl_handler.zh = function() - api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.zh.line, 0, -1) - for i = 1, pos_info.zh.content, 1 do - api.nvim_buf_add_highlight(buf, -1, hl.zh, pos_info.zh.line + i, 0, -1) - end -end - -hl_handler.en = function() - if pos_info.en then - api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.en.line, 0, -1) - for i = 1, pos_info.en.content, 1 do - api.nvim_buf_add_highlight(buf, -1, hl.en, pos_info.en.line + i, 0, -1) - end - end -end - - -local function set_hl() - for _, v in ipairs(order) do - hl_handler[v]() - end -end - -local function clear_tmp_info() - pos_info = {} - line = 0 -end - -local function get_visual_selection() +local function get_select() local s_start = vim.fn.getpos("'<") local s_end = vim.fn.getpos("'>") - assert(s_end[2] == s_start[2]) + if s_start[2] ~= s_start[2] then + error('TODO: multiline translate') + end local lin = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)[1] local word = string.sub(lin, s_start[3], s_end[3]) return word end -function M.query(mode) - assert(buf > 0) +local function get_query_res(method) + -- NOTE : get query word local word = '' - if mode == 'n' then + if method == 'cursor' then word = vim.fn.expand('') - elseif mode == 'v' then - word = get_visual_selection() - elseif mode == 'I' then - word = vim.fn.input('请输入您要查询的单词: ') - -- vim.ui.input({prompt = '请输入您要查询的单词: '}, function (input) - -- word = input - -- end) + elseif method == 'select' then + word = get_select():match('%s+') + elseif method == 'input' then + word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder else - error('mode argument is invalid') + error('unknown method') end - local res = require("Trans.database").query(word) - local width, height = set_text(res) - show_win(width, height) - if res then - set_hl() - clear_tmp_info() - end - - if auto_close then - api.nvim_create_autocmd( - { 'InsertEnter', 'CursorMoved', 'BufLeave', }, { - buffer = 0, - once = true, - callback = M.close_win, - }) - end + -- TODO : dict query optimization + local res = dict:select('stardict', { + where = { word = arg }, + }) + return res[1] end -function M.query_cursor() - M.query('n') +M.TransLate = function(opts) + local res = get_query_res(opts.method) + -- TODO <++> end -function M.query_select() - M.query('v') -end -function M.query_input() - M.query('I') -end - -function M.close_win() - if win > 0 then - api.nvim_win_close(win, true) - win = 0 - end -end - --- function M.enter_win() --- if api.nvim_win_is_valid(win) then --- else --- error('current win is not valid') +-- local win = 0 +-- local line = 0 +-- local pos_info = {} +-- +-- local handler = {} +-- api.nvim_buf_set_option(buf, 'filetype', 'Trans') +-- +-- local function show_win(width, height) +-- end +-- +-- -- NOTE title +-- handler.title = function(text, query_res) +-- local title = ('%s [%s] %s %s'):format( +-- query_res.word, +-- query_res.phonetic, +-- (display.oxford and (query_res.oxford == 1 and icon.isOxford or icon.notOxford) or ''), +-- ((display.collins_star and query_res.collins) and string.rep(icon.star, query_res.collins) or '') +-- ) +-- table.insert(text, title) +-- +-- pos_info.title = {} +-- pos_info.title.word = #query_res.word +-- pos_info.title.phonetic = query_res.phonetic and #query_res.phonetic or 3 +-- pos_info.title.line = line +-- line = line + 1 +-- end +-- +-- -- NOTE tag +-- handler.tag = function(text, query_res) +-- if query_res.tag and #query_res.tag > 0 then +-- local tag = query_res.tag:gsub('zk', '中考'):gsub('gk', '高考'):gsub('ky', '考研'):gsub('cet4', '四级'): +-- gsub('cet6', '六级'):gsub('ielts', '雅思'):gsub('toefl', '托福'):gsub('gre', 'GRE') +-- +-- table.insert(text, '标签:') +-- table.insert(text, ' ' .. tag) +-- table.insert(text, '') +-- +-- pos_info.tag = line +-- line = line + 3 -- end -- end - -return M +-- +-- -- NOTE pos 词性 +-- handler.pos = function(text, query_res) +-- if query_res.pos and #query_res.pos > 0 then +-- table.insert(text, '词性:') +-- +-- local content = 0 +-- for v in vim.gsplit(query_res.pos, [[/]]) do +-- table.insert(text, string.format(' %s', v .. '%')) +-- content = content + 1 +-- end +-- +-- table.insert(text, '') +-- +-- pos_info.pos = {} +-- pos_info.pos.line = line +-- pos_info.pos.content = content +-- line = line + content + 2 +-- end +-- end +-- +-- -- NOTE exchange +-- handler.exchange = function(text, query_res) +-- if query_res.exchange and #query_res.exchange > 0 then +-- table.insert(text, '词形变化:') +-- +-- local exchange_map = { +-- p = '过去式', +-- d = '过去分词', +-- i = '现在分词', +-- r = '形容词比较级', +-- t = '形容词最高级', +-- s = '名词复数形式', +-- O = '词干', +-- ['3'] = '第三人称单数', +-- } +-- +-- local content = 0 +-- for v in vim.gsplit(query_res.exchange, [[/]]) do +-- table.insert(text, string.format(' %s: %s', exchange_map[v:sub(1, 1)], v:sub(3))) +-- content = content + 1 +-- -- FIXME: 中文字符与字母位宽不一致, 暂时无法对齐 +-- end +-- table.insert(text, '') +-- +-- pos_info.exchange = {} +-- pos_info.exchange.line = line +-- pos_info.exchange.content = content +-- line = line + content + 2 +-- end +-- end +-- +-- -- NOTE 中文翻译 +-- handler.zh = function(text, query_res) +-- if query_res.translation then +-- table.insert(text, '中文翻译:') +-- +-- local content = 0 +-- for v in vim.gsplit(query_res.translation, '\n') do +-- table.insert(text, ' ' .. v) +-- content = content + 1 +-- end +-- table.insert(text, '') +-- +-- pos_info.zh = {} +-- pos_info.zh.line = line +-- pos_info.zh.content = content +-- line = content + line + 2 +-- end +-- end +-- +-- -- NOTE 英文翻译 +-- handler.en = function(text, query_res) +-- if query_res.definition and #query_res.definition > 0 then +-- table.insert(text, '英文翻译:') +-- +-- local content = 0 +-- for v in vim.gsplit(query_res.definition, '\n') do +-- table.insert(text, ' ' .. v) +-- content = content + 1 +-- end +-- table.insert(text, '') +-- +-- pos_info.en = {} +-- pos_info.en.line = line +-- pos_info.en.content = content +-- line = line + content + 2 +-- end +-- end +-- +-- -- @return string array +-- local function get_text(query_res) +-- local text = {} +-- for _, v in ipairs(order) do +-- handler[v](text, query_res) +-- end +-- return text +-- end +-- +-- local function set_text(query_res) +-- local text = query_res and get_text(query_res) or { '没有找到相关定义' } +-- +-- api.nvim_buf_set_lines(buf, 0, -1, false, text) +-- local width = 0 +-- for _, v in ipairs(text) do +-- if #v > width then +-- width = v:len() +-- end +-- end +-- return width, #text +-- end +-- +-- local hl_handler = {} +-- +-- hl_handler.title = function() +-- api.nvim_buf_add_highlight(buf, -1, hl.word, pos_info.title.line, 0, pos_info.title.word) +-- api.nvim_buf_add_highlight(buf, -1, hl.phonetic, pos_info.title.line, pos_info.title.word + 5, +-- pos_info.title.word + 5 + pos_info.title.phonetic) +-- end +-- +-- hl_handler.tag = function() +-- if pos_info.tag then +-- api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.tag, 0, -1) +-- api.nvim_buf_add_highlight(buf, -1, hl.tag, pos_info.tag + 1, 0, -1) +-- end +-- end +-- +-- hl_handler.pos = function() +-- if pos_info.pos then +-- api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.pos.line, 0, -1) +-- for i = 1, pos_info.pos.content, 1 do +-- api.nvim_buf_add_highlight(buf, -1, hl.pos, pos_info.pos.line + i, 0, -1) +-- end +-- end +-- end +-- +-- hl_handler.exchange = function() +-- if pos_info.exchange then +-- api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.exchange.line, 0, -1) +-- for i = 1, pos_info.exchange.content, 1 do +-- api.nvim_buf_add_highlight(buf, -1, hl.exchange, pos_info.exchange.line + i, 0, -1) +-- end +-- end +-- end +-- +-- hl_handler.zh = function() +-- api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.zh.line, 0, -1) +-- for i = 1, pos_info.zh.content, 1 do +-- api.nvim_buf_add_highlight(buf, -1, hl.zh, pos_info.zh.line + i, 0, -1) +-- end +-- end +-- +-- hl_handler.en = function() +-- if pos_info.en then +-- api.nvim_buf_add_highlight(buf, -1, hl.ref, pos_info.en.line, 0, -1) +-- for i = 1, pos_info.en.content, 1 do +-- api.nvim_buf_add_highlight(buf, -1, hl.en, pos_info.en.line + i, 0, -1) +-- end +-- end +-- end +-- +-- +-- local function set_hl() +-- for _, v in ipairs(order) do +-- hl_handler[v]() +-- end +-- end +-- +-- local function clear_tmp_info() +-- pos_info = {} +-- line = 0 +-- end +-- +-- +-- function M.query(mode) +-- assert(buf > 0) +-- local word = '' +-- if mode == 'n' then +-- word = vim.fn.expand('') +-- elseif mode == 'v' then +-- word = get_visual_selection() +-- elseif mode == 'I' then +-- word = vim.fn.input('请输入您要查询的单词: ') +-- -- vim.ui.input({prompt = '请输入您要查询的单词: '}, function (input) +-- -- word = input +-- -- end) +-- else +-- error('mode argument is invalid') +-- end +-- +-- local res = require("Trans.database").query(word) +-- local width, height = set_text(res) +-- show_win(width, height) +-- if res then +-- set_hl() +-- clear_tmp_info() +-- end +-- +-- if auto_close then +-- api.nvim_create_autocmd( +-- { 'InsertEnter', 'CursorMoved', 'BufLeave', }, { +-- buffer = 0, +-- once = true, +-- callback = M.close_win, +-- }) +-- end +-- end +-- +-- function M.query_cursor() +-- M.query('n') +-- end +-- +-- function M.query_select() +-- M.query('v') +-- end +-- +-- function M.query_input() +-- M.query('I') +-- end +-- +-- function M.close_win() +-- if win > 0 then +-- api.nvim_win_close(win, true) +-- win = 0 +-- end +-- end +-- +-- -- function M.enter_win() +-- -- if api.nvim_win_is_valid(win) then +-- -- else +-- -- error('current win is not valid') +-- -- end +-- -- end +-- +-- return M diff --git a/lua/Trans/highlight.lua b/lua/Trans/highlight.lua deleted file mode 100644 index 23a4f72..0000000 --- a/lua/Trans/highlight.lua +++ /dev/null @@ -1,26 +0,0 @@ -local M = {} - -M.hlgroup = { - word = 'TransWord', - phonetic = 'TransPhonetic', - ref = 'TransRef', - tag = 'TransTag', - exchange = 'TransExchange', - pos = 'TransPos', - zh = 'TransZh', - en = 'TransEn', -} - -function M.set_hl() - local set_hl = vim.api.nvim_set_hl - set_hl(0, M.hlgroup.word, { fg = '#7ee787', bold = true }) - set_hl(0, M.hlgroup.phonetic, { fg = '#8b949e' }) - set_hl(0, M.hlgroup.ref, { fg = '#75beff', bold = true }) - set_hl(0, M.hlgroup.tag, { fg = '#e5c07b' }) - set_hl(0, M.hlgroup.pos, { link = M.hlgroup.tag }) - set_hl(0, M.hlgroup.exchange, { link = M.hlgroup.tag }) - set_hl(0, M.hlgroup.zh, { link = M.hlgroup.word }) - set_hl(0, M.hlgroup.en, { fg = '#bc8cff' }) -end - -return M diff --git a/lua/Trans/setup.lua b/lua/Trans/setup.lua index 88d1ddf..e0325b0 100644 --- a/lua/Trans/setup.lua +++ b/lua/Trans/setup.lua @@ -1,7 +1,6 @@ local db = require("Trans").db -- local conf = require("Trans").conf - vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.display").query_cursor, {}) vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.display").query_select, {}) vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.display").query_input, {}) @@ -20,4 +19,8 @@ vim.api.nvim_create_autocmd('VimLeave', { -- vim.keymap.set('n', 'mm', 'TranslateCurosorWord') -- vim.keymap.set('v', 'mm', 'TranslateSelectWord') -require("Trans.highlight").set_hl() + +local highlights = require("Trans").conf.highlight +for highlight, opt in pairs(highlights) do + vim.nvim_set_hl(0, highlight, opt) +end diff --git a/lua/Trans/window.lua b/lua/Trans/window.lua new file mode 100644 index 0000000..e02eb5c --- /dev/null +++ b/lua/Trans/window.lua @@ -0,0 +1,48 @@ +-- TODO different style to display +local M = {} + +M.float_opts = function(conf) + local columns = vim.o.columns + local height = vim.o.lines - vim.o.cmdheight - conf.top_offset + local width = math.floor(columns * conf.relative_width) + + return { + relative = 'editor', + col = math.floor((columns - width) / 2), -- 两侧的宽度 + row = conf.top_offset, + title = 'Trans', + title_pos = 'center', + style = 'minimal', + width = width, + height = height, + border = conf.border, + zindex = 50, + } +end + +M.cursor_opts = function (conf) + local opts = { + relative = 'cursor', + col = 2, + row = 2, + title = 'Trans', + title_pos = 'center', + style = 'minimal', + border = conf.border, + -- TODO keymap to convert style to Float + focusable = false, + zindex = 100, + } + if conf.style == 'fixed' then + opts.width = conf.width + opts.height = conf.height + elseif conf.style == 'relative' then + opts.width = (conf.width > 0 and conf.width < conf.max_width) and conf.width or conf.max_width + opts.height = (conf.height > 0 and conf.height < conf.max_height) and conf.height or conf.max_height + else + error('unknown style!') + end + return opts +end + +return M