Merge pull request #2 from JuanZoran/experimental
重写了content逻辑,删掉无用的配置,完善了hover ui样式
This commit is contained in:
commit
fc8a727d69
100
README.md
100
README.md
@ -96,36 +96,73 @@ use {
|
||||
|
||||
## 配置
|
||||
```lua
|
||||
require'Trans'.setup{
|
||||
display = {
|
||||
style = 'minimal',
|
||||
max_height = 50, -- 小于0代表无限制
|
||||
max_width = 50,
|
||||
collins_star = true, -- 是否显示柯林斯星级
|
||||
oxford = true, -- 是否显示为牛津3000词汇
|
||||
wrap = true, -- 是否折叠超出width的部分
|
||||
border_style = 'rounded', -- 边框属性
|
||||
view = 'cursor', -- TODO, 目前还未测试, 请不要更改
|
||||
offset_x = 2, -- 弹窗相对光标的偏移
|
||||
offset_y = 2,
|
||||
require'Trans'.setup {
|
||||
view = {
|
||||
input = 'hover',
|
||||
n = 'hover',
|
||||
v = 'hover',
|
||||
},
|
||||
order = { -- 排版的顺序
|
||||
'title', -- 如果你不想显示某一部分, 可以直接删除该部分
|
||||
window = {
|
||||
border = 'rounded',
|
||||
hover = {
|
||||
width = 36,
|
||||
height = 23,
|
||||
},
|
||||
float = {
|
||||
width = 0.8,
|
||||
height = 0.8,
|
||||
},
|
||||
},
|
||||
|
||||
order = {
|
||||
-- offline = {
|
||||
'title',
|
||||
'tag',
|
||||
'pos',
|
||||
'exchange',
|
||||
'zh',
|
||||
'en',
|
||||
'translation',
|
||||
-- NOTE :如果你想限制某个组件的行数,可以设置max_size
|
||||
-- { 'Definition', max_size = 4 },
|
||||
'definition',
|
||||
-- },
|
||||
-- online = {
|
||||
-- -- TODO
|
||||
-- },
|
||||
},
|
||||
|
||||
db_path = '$HOME/.vim/dict/ultimate.db', -- 词典的数据库位置
|
||||
-- 如果你是手动安装, 可以自定义
|
||||
icon = {
|
||||
star = '⭐', -- 柯林斯星级图标
|
||||
isOxford = '✔', -- 牛津3000词汇的标志
|
||||
notOxford = ''
|
||||
star = '',
|
||||
notfound = '',
|
||||
yes = '',
|
||||
no = ''
|
||||
-- star = '⭐',
|
||||
-- notfound = '❔',
|
||||
-- yes = '✔️',
|
||||
-- no = '❌'
|
||||
},
|
||||
auto_close = true, -- 移动光标关闭弹窗
|
||||
db_path = '$HOME/.vim/dict/ultimate.db',
|
||||
-- TODO :
|
||||
-- engine = {
|
||||
-- -- TODO
|
||||
-- 'offline',
|
||||
-- }
|
||||
map = {
|
||||
-- TODO
|
||||
hover = {
|
||||
pageup = '<C-u>',
|
||||
pagedown = '<C-d>',
|
||||
},
|
||||
},
|
||||
-- history = {
|
||||
-- -- TOOD
|
||||
-- }
|
||||
|
||||
-- TODO add online translate engine
|
||||
-- online_search = {
|
||||
-- enable = false,
|
||||
-- engine = {},
|
||||
-- }
|
||||
|
||||
-- TODO register word
|
||||
}
|
||||
```
|
||||
|
||||
@ -134,25 +171,14 @@ require'Trans'.setup{
|
||||
> 示例中展示, 将`mm`映射成快捷键
|
||||
```lua
|
||||
-- normal-mode
|
||||
vim.keymap.set('n', 'mm', '<Cmd>TranslateCursorWord<CR>')
|
||||
|
||||
-- visual-mode
|
||||
vim.keymap.set('v', 'mm', '<Esc><Cmd>TranslateSelectWord<CR>')
|
||||
vim.keymap.set({'n', 'v'}, 'mm', '<Cmd>Translate<CR>')
|
||||
vim.keymap.set('n', 'mi', '<Cmd>TranslateInput<CR>')
|
||||
|
||||
```
|
||||
|
||||
## 高亮组
|
||||
```lua
|
||||
hlgroup = {
|
||||
word = 'TransWord',
|
||||
phonetic = 'TransPhonetic',
|
||||
ref = 'TransRef', -- 如: 标签: | 中文翻译: 之类的前导词
|
||||
tag = 'TransTag',
|
||||
exchange = 'TransExchange',
|
||||
pos = 'TransPos',
|
||||
zh = 'TransZh',
|
||||
en = 'TransEn',
|
||||
}
|
||||
-- TODO : add explanation
|
||||
|
||||
```
|
||||
## 声明
|
||||
|
58
lua/Trans/README.md
Normal file
58
lua/Trans/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# 字段说明
|
||||
|
||||
## 本地
|
||||
- `word`
|
||||
查询的字符串
|
||||
- `phonetic`
|
||||
音标
|
||||
- `collins`
|
||||
柯林斯星级: integer
|
||||
- `oxford`
|
||||
是否为牛津词汇: integer (1为是)
|
||||
- `tag`
|
||||
标签
|
||||
- `pos`
|
||||
词性
|
||||
- `exchange`
|
||||
词态变化
|
||||
- `translation`
|
||||
中文翻译
|
||||
- `definition`
|
||||
英文注释
|
||||
|
||||
## 有道
|
||||
### 中英
|
||||
|
||||
basic JSONObject 简明释义
|
||||
phonetic text 词典音标
|
||||
usPhonetic text 美式音标
|
||||
ukPhonetic text 英式音标
|
||||
ukSpeech text 英式发音
|
||||
usSpeech text 美式发音
|
||||
explains text 基本释义
|
||||
text text 短语
|
||||
explain String Array 词义解释列表
|
||||
wordFormats Object Array 单词形式变化列表
|
||||
name String 形式名称,例如:复数
|
||||
web JSONArray 网络释义
|
||||
phrase String 词组
|
||||
meaning String 含义
|
||||
synonyms JSONObject 近义词
|
||||
pos String 词性
|
||||
words String Array 近义词列表
|
||||
trans String 释义
|
||||
antonyms ObjectArray 反义词
|
||||
relatedWords JSONArray 相关词
|
||||
wordNet JSONObject 汉语词典网络释义
|
||||
phonetic String 发音
|
||||
meanings ObjectArray 释义
|
||||
meaning String 释义
|
||||
example array 示例
|
||||
dict String 词典deeplink
|
||||
webDict String 词典网页deeplink
|
||||
sentenceSample text 例句
|
||||
sentence text 例句
|
||||
sentenceBold text 将查询内容加粗的例句
|
||||
translation text 例句翻译
|
||||
wfs text 单词形式变化
|
||||
exam_type text 考试类型
|
@ -1,7 +1,132 @@
|
||||
# API说明
|
||||
|
||||
## 概述
|
||||
- 翻译查询
|
||||
- ``
|
||||
- 字段处理
|
||||
- 窗口显示
|
||||
<!--toc:start-->
|
||||
- [API说明](#api说明)
|
||||
- [数据结构](#数据结构)
|
||||
- [翻译](#翻译)
|
||||
- [窗口](#窗口)
|
||||
- [翻译结果](#翻译结果)
|
||||
- [内容单位](#内容单位)
|
||||
- [窗口绘制逻辑](#窗口绘制逻辑)
|
||||
- [hover](#hover)
|
||||
- [float](#float)
|
||||
<!--toc:end-->
|
||||
|
||||
## 数据结构
|
||||
|
||||
### 翻译
|
||||
- `word`
|
||||
待翻译的字符串: string
|
||||
- `sentence`
|
||||
是否为句子: boolean
|
||||
- `result`
|
||||
翻译查询的结果: table
|
||||
> 见: [翻译结果](#翻译结果)
|
||||
- `engine`
|
||||
|
||||
### 窗口
|
||||
- `style`
|
||||
风格: string
|
||||
- `height`
|
||||
高度: integer
|
||||
- `width`
|
||||
宽度: integer
|
||||
- `border`
|
||||
边框样式: string
|
||||
- `winhl`
|
||||
窗口的高亮: string
|
||||
|
||||
### 翻译结果
|
||||
**无特殊说明, 所有字段均为`string`类型**
|
||||
|
||||
- `word`
|
||||
查询的字符串
|
||||
- `phonetic`
|
||||
音标
|
||||
- `collins`
|
||||
柯林斯星级: integer
|
||||
- `oxford`
|
||||
是否为牛津词汇: integer (1为是)
|
||||
- `tag`
|
||||
标签
|
||||
- `pos`
|
||||
词性
|
||||
- `exchange`
|
||||
词态变化
|
||||
- `translation`
|
||||
中文翻译
|
||||
- `definition`
|
||||
英文注释
|
||||
|
||||
|
||||
### 内容单位
|
||||
- `field` 字段
|
||||
> 是展示的最小单位
|
||||
|
||||
**属性**
|
||||
- `1`
|
||||
存储的文本: string
|
||||
- `2` (optional)
|
||||
对应的高亮: string
|
||||
- `_start`
|
||||
起始行: integer
|
||||
- `_end`
|
||||
结束行: integer
|
||||
> **注意:** `_start` 和`_end` 字段只有已经被展示到窗口后才会被设置
|
||||
|
||||
**方法**
|
||||
- 无
|
||||
|
||||
- `line` 行
|
||||
> 窗口展示的每一行, 一个行有多个`field`
|
||||
|
||||
**属性**
|
||||
- `text`
|
||||
当前保存的字符串: string
|
||||
- `hls`
|
||||
行内的高亮: table
|
||||
- `index`
|
||||
行号[0为起始下标]
|
||||
- `fields`
|
||||
行内保存的`field`
|
||||
- `status`
|
||||
行内是否需要更新: boolean
|
||||
> **注意:** `num` 只有已经被展示到窗口后才会被设置
|
||||
|
||||
**方法**
|
||||
- `update`
|
||||
更新`text`和`hls`
|
||||
- `data`
|
||||
获取行的text
|
||||
- `insert`
|
||||
添加新`field`
|
||||
- `add_highlight`
|
||||
添加高亮
|
||||
> 参数: bufnr
|
||||
|
||||
- `content` 内容
|
||||
> 窗口展示的单位, 一个内容内有多个`line`
|
||||
|
||||
**方法**
|
||||
- `data`
|
||||
返回lines和highlights
|
||||
- `insert`
|
||||
插入新的行
|
||||
- `attach`
|
||||
将内容展示到buffer
|
||||
> 参数: bufnr
|
||||
|
||||
# 窗口绘制逻辑
|
||||
|
||||
- 获取所有组件
|
||||
## hover
|
||||
- 按照order顺序加载
|
||||
- 按组件间距为4计算组件个数能否在一行以内放下
|
||||
- 放不下则按照组件间距为4 计算组件个数并对齐
|
||||
- 放得下则重新计算组间距
|
||||
|
||||
获得组件行内容, 设置到行内
|
||||
获取组件高亮, 设置高亮
|
||||
|
||||
## float
|
||||
由定义好的逻辑,绘制整个窗口
|
||||
|
@ -3,23 +3,12 @@ local _, db = pcall(require, 'sqlite.db')
|
||||
if not _ then
|
||||
error('Please check out sqlite.lua')
|
||||
end
|
||||
local type_check = vim.validate
|
||||
|
||||
-- INFO : init database
|
||||
local path = require("Trans.conf.loader").loaded_conf.base.db_path
|
||||
local path = require('Trans').conf.db_path
|
||||
local dict = db:open(path)
|
||||
|
||||
-- INFO :Auto Close
|
||||
vim.api.nvim_create_autocmd('VimLeavePre', {
|
||||
group = require("Trans").augroup,
|
||||
callback = function()
|
||||
if db:isopen() then
|
||||
db:close()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local query_field = {
|
||||
local query_fields = {
|
||||
'word',
|
||||
'phonetic',
|
||||
'definition',
|
||||
@ -31,19 +20,40 @@ local query_field = {
|
||||
'exchange',
|
||||
}
|
||||
|
||||
-- NOTE : local query
|
||||
M.query = function(arg)
|
||||
-- TODO : more opts
|
||||
type_check {
|
||||
arg = { arg, 'string' },
|
||||
}
|
||||
|
||||
local routes = {
|
||||
offline = function(word)
|
||||
local res = dict:select('stardict', {
|
||||
where = {
|
||||
word = arg,
|
||||
word = word,
|
||||
},
|
||||
keys = query_field,
|
||||
keys = query_fields,
|
||||
})
|
||||
return res[1]
|
||||
end,
|
||||
}
|
||||
|
||||
|
||||
-- INFO :Auto Close
|
||||
vim.api.nvim_create_autocmd('VimLeavePre', {
|
||||
group = require("Trans").augroup,
|
||||
callback = function()
|
||||
if db:isopen() then
|
||||
db:close()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
-- NOTE : local query
|
||||
M.query = function(engine, word)
|
||||
-- TODO : more opts
|
||||
vim.validate {
|
||||
word = {word, 's'},
|
||||
engine = {word, 's'},
|
||||
}
|
||||
|
||||
return routes[engine](word)
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,143 +0,0 @@
|
||||
local M = {}
|
||||
local type_check = vim.validate
|
||||
M.__index = M
|
||||
M.lines = {}
|
||||
M.highlight = {}
|
||||
M.height = 0
|
||||
M.width = 0
|
||||
M.interval = ' '
|
||||
M.opts = {}
|
||||
|
||||
|
||||
|
||||
function M:new(opts)
|
||||
if opts then
|
||||
self.opts = opts
|
||||
end
|
||||
|
||||
local content = {}
|
||||
setmetatable(content, self)
|
||||
return content
|
||||
end
|
||||
|
||||
-- NOTE :
|
||||
-- local items = {
|
||||
-- -- style1: string 不需要单独设置高亮的情况
|
||||
-- 'text',
|
||||
-- -- style2: string[] 需要设置高亮,第二个名称为高亮组
|
||||
-- {'text2', 'highlight name'},
|
||||
-- }
|
||||
|
||||
-- local opts = {
|
||||
-- -- 可选的参数
|
||||
-- highlight = 'highlight name' -- string 该行的高亮
|
||||
-- indent = 4 -- integer 该行的应该在开头的缩进
|
||||
-- interval = 4 -- integer 该行组件的间隔
|
||||
-- }
|
||||
function M:insert(items)
|
||||
type_check {
|
||||
items = { items, 'table' },
|
||||
}
|
||||
|
||||
self.height = self.height + 1 -- line数加一
|
||||
|
||||
local line = {
|
||||
indent = items.indent,
|
||||
highlight = items.highlight,
|
||||
}
|
||||
|
||||
local highlight = {}
|
||||
|
||||
|
||||
for i, item in ipairs(items) do
|
||||
if type(item) == 'string' then
|
||||
item = { item }
|
||||
end
|
||||
line[i] = item[1]
|
||||
if item[2] then
|
||||
highlight[i] = item[2]
|
||||
end
|
||||
end
|
||||
|
||||
self.highlight[self.height] = highlight
|
||||
self.lines[self.height] = line
|
||||
end
|
||||
|
||||
---Usage:
|
||||
--- local buffer_id
|
||||
--- local lines, highlights = M:lines()
|
||||
--- vim.api.nvim_buf_set_lines(buffer_id, 0, -1, false,lines)
|
||||
--- for i, hl in ipairs(highlights) do
|
||||
--- vim.api.nvim_buf_add_highlight(buffer_id, 0, hl.name, i, hl._start, hl._end)
|
||||
--- end
|
||||
---@return table line
|
||||
---@return table highlight
|
||||
function M:data()
|
||||
-- NOTE 返回格式化的行,如果需要高亮,则第二个参数返回高亮
|
||||
local lines = {}
|
||||
local highlights = {}
|
||||
|
||||
for index = 1, #self.lines do
|
||||
local line = ''
|
||||
local highlight = {}
|
||||
local l = self.lines[index]
|
||||
local hl = self.highlight[index]
|
||||
if l.indent then
|
||||
line = (' '):rep(l.indent)
|
||||
end
|
||||
|
||||
if l.highlight then
|
||||
line = line .. table.concat(l, self.interval)
|
||||
highlight[1] = { name = l.highlight, _start = 1, _end = -1 }
|
||||
|
||||
else
|
||||
line = line .. l[1]
|
||||
|
||||
if hl[1] then
|
||||
-- WARN :可能需要设置成字符串宽度!!!
|
||||
table.insert(highlight, { name = hl[1], _start = #line - #l[1], _end = #line })
|
||||
end
|
||||
|
||||
for i = 2, #l do
|
||||
line = line .. self.interval .. l[i]
|
||||
if hl[i] then
|
||||
local _end = #line
|
||||
table.insert(highlight, { name = hl[i], _start = _end - #l[i], _end = _end })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lines[index] = line
|
||||
local len = #line
|
||||
if self.width < len then
|
||||
self.width = len
|
||||
end
|
||||
highlights[index] = highlight
|
||||
end
|
||||
return lines, highlights
|
||||
end
|
||||
|
||||
|
||||
function M:attach()
|
||||
local height = self.opts.win.height
|
||||
local width = self.opts.win.width
|
||||
|
||||
local lines, hls = self:data()
|
||||
vim.api.nvim_buf_set_lines(self.opts.bufnr, 0, -1, false, lines)
|
||||
|
||||
for line, l_hl in ipairs(hls) do
|
||||
for _, hl in ipairs(l_hl) do
|
||||
vim.api.nvim_buf_add_highlight(self.opts.bufnr, -1, hl.name, line - 1, hl._start, hl._end)
|
||||
end
|
||||
end
|
||||
|
||||
if self.height < height then
|
||||
vim.api.nvim_win_set_height(self.opts.winid, self.height)
|
||||
end
|
||||
|
||||
if self.width < width then
|
||||
vim.api.nvim_win_set_width(self.opts.winid, self.width)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -1,20 +0,0 @@
|
||||
local M = {}
|
||||
M.__index = M
|
||||
M.len = 0
|
||||
|
||||
function M:new()
|
||||
local items = {}
|
||||
setmetatable(items, self)
|
||||
return items
|
||||
end
|
||||
|
||||
function M:insert(item, highlight)
|
||||
table.insert(self, item)
|
||||
self.len = self.len + #item
|
||||
end
|
||||
|
||||
function M:format(win_width)
|
||||
|
||||
end
|
||||
|
||||
return M
|
@ -1,68 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.component = function (field, max_size)
|
||||
if field.definition and field.definition ~= '' then
|
||||
local ref = {
|
||||
{ '英文注释', 'TransRef' }
|
||||
}
|
||||
|
||||
local definitions = {
|
||||
highlight = 'TransDefinition',
|
||||
needformat = true,
|
||||
indent = 4,
|
||||
}
|
||||
local size = 0
|
||||
for defin in vim.gsplit(field.definition, '\n', true) do
|
||||
if defin ~= '' then
|
||||
table.insert(definitions, defin)
|
||||
|
||||
size = size + 1
|
||||
if size == max_size then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return { ref, definitions }
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
--[[n a formation of people or things one beside another
|
||||
n a mark that is long relative to its width
|
||||
n a formation of people or things one behind another
|
||||
n a length (straight or curved) without breadth or thickness; the trace of a moving point
|
||||
n text consisting of a row of words written across a page or computer screen
|
||||
n a single frequency (or very narrow band) of radiation in a spectrum
|
||||
n a fortified position (especially one marking the most forward position of troops)
|
||||
n a course of reasoning aimed at demonstrating a truth or falsehood; the methodical process of logical reasoning
|
||||
n a conductor for transmitting electrical or optical signals or electric power
|
||||
n a connected series of events or actions or developments
|
||||
n a spatial location defined by a real or imaginary unidimensional extent
|
||||
n a slight depression in the smoothness of a surface
|
||||
n a pipe used to transport liquids or gases
|
||||
n the road consisting of railroad track and roadbed
|
||||
n a telephone connection
|
||||
n acting in conformity
|
||||
n the descendants of one individual
|
||||
n something (as a cord or rope) that is long and thin and flexible
|
||||
n the principal activity in your life that you do to earn money
|
||||
n in games or sports; a mark indicating positions or bounds of the playing area
|
||||
n (often plural) a means of communication or access
|
||||
n a particular kind of product or merchandise
|
||||
n a commercial organization serving as a common carrier
|
||||
n space for one line of print (one column wide and 1/14 inch deep) used to measure advertising
|
||||
n the maximum credit that a customer is allowed
|
||||
n a succession of notes forming a distinctive sequence
|
||||
n persuasive but insincere talk that is usually intended to deceive or impress
|
||||
n a short personal letter
|
||||
n a conceptual separation or distinction
|
||||
n mechanical system in a factory whereby an article is conveyed through sites at which successive operations are performed on it
|
||||
v be in line with; form a line along
|
||||
v cover the interior of
|
||||
v make a mark or lines on a surface
|
||||
v mark with lines
|
||||
v fill plentifully
|
||||
v reinforce with fabric
|
||||
--]]
|
@ -1,45 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
local exchange_map = {
|
||||
p = '过去式',
|
||||
d = '过去分词',
|
||||
i = '现在分词',
|
||||
r = '形容词比较级',
|
||||
t = '形容词最高级',
|
||||
s = '名词复数形式',
|
||||
f = '第三人称单数',
|
||||
['0'] = '词根',
|
||||
['1'] = '词根的变化形式',
|
||||
['3'] = '第三人称单数',
|
||||
}
|
||||
|
||||
M.component = function(field)
|
||||
-- TODO
|
||||
if field.exchange and field.exchange ~= '' then
|
||||
local ref = {
|
||||
{ '词型变化', 'TransRef' },
|
||||
}
|
||||
local exchanges = {
|
||||
needformat = true,
|
||||
highlight = 'TransExchange',
|
||||
indent = 4,
|
||||
emptyline = true,
|
||||
}
|
||||
|
||||
for _exchange in vim.gsplit(field.exchange, '/', true) do
|
||||
local prefix = exchange_map[_exchange:sub(1, 1)]
|
||||
if prefix then
|
||||
local exchange = prefix .. _exchange:sub(2)
|
||||
-- local exchange = exchange_map[_exchange:sub(1, 1)] .. _exchange:sub(2)
|
||||
table.insert(exchanges, exchange)
|
||||
|
||||
else
|
||||
error('add exchange_map for [' .. _exchange .. ']')
|
||||
end
|
||||
end
|
||||
|
||||
return { ref, exchanges }
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -1,20 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.component = function(field)
|
||||
-- TODO
|
||||
if field.pos and field.pos ~= '' then
|
||||
local ref = {
|
||||
{ '词性:', 'TransRef' },
|
||||
}
|
||||
local pos = {
|
||||
{ field.pos },
|
||||
highlight = 'TransPos',
|
||||
indent = 4,
|
||||
emptyline = true,
|
||||
}
|
||||
|
||||
return { ref, pos }
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -1,46 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
local tag_map = {
|
||||
zk = '中考',
|
||||
gk = '高考',
|
||||
ky = '考研',
|
||||
cet4 = '四级',
|
||||
cet6 = '六级',
|
||||
ielts = '雅思',
|
||||
toefl = '托福',
|
||||
gre = 'GRE',
|
||||
}
|
||||
|
||||
---从查询结果中获取字符串
|
||||
---@param field table 查询的结果
|
||||
---@return component? component 提取的组件信息[包含多个组件]
|
||||
M.component = function(field)
|
||||
-- TODO
|
||||
if field.tag and field.tag ~= '' then
|
||||
local ref = {
|
||||
{ '标签:', 'TransRef' },
|
||||
}
|
||||
|
||||
local tags = {
|
||||
needformat = true,
|
||||
highlight = 'TransTag',
|
||||
indent = 4,
|
||||
emptyline = true,
|
||||
}
|
||||
|
||||
for _tag in vim.gsplit(field.tag, ' ', true) do
|
||||
local tag = tag_map[_tag]
|
||||
|
||||
if tag then
|
||||
table.insert(tags, tag)
|
||||
else
|
||||
error('add tag_map for [' .. _tag .. ']')
|
||||
end
|
||||
end
|
||||
|
||||
return { ref, tags }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
@ -1,67 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
local display = require("Trans.conf.loader").loaded_conf.ui.display
|
||||
local icon = require("Trans.conf.loader").loaded_conf.ui.icon
|
||||
|
||||
-- {
|
||||
-- collins = 3,
|
||||
-- definition = "n. an expression of greeting",
|
||||
-- exchange = "s:hellos",
|
||||
-- oxford = 1,
|
||||
-- phonetic = "hə'ləʊ",
|
||||
-- pos = "u:97/n:3",
|
||||
-- tag = "zk gk",
|
||||
-- translation = "n. 表示问候, 惊奇或唤起注意时的用语\nint. 喂;哈罗\nn. (Hello)人名;(法)埃洛",
|
||||
-- word = "hello"
|
||||
-- }
|
||||
|
||||
|
||||
-- local data = {
|
||||
-- { word, 'TransWord' },
|
||||
-- -- NOTE :如果平配置设置显示,并且数据库中存在则有以下字段
|
||||
-- { phonetic, 'TransPhonetic' },
|
||||
-- collins,
|
||||
-- oxford
|
||||
-- -- { phonetic, 'TransPhonetic' },
|
||||
-- }
|
||||
|
||||
|
||||
---@alias items
|
||||
---| 'string[]' # 所有组件的信息
|
||||
---| 'needformat?'# 是否需要格式化
|
||||
---| 'highlight?' # 整个组件的高亮
|
||||
---| 'indent?' # 每行整体的缩进
|
||||
---@alias component items[]
|
||||
---从查询结果中获取字符串
|
||||
---@param field table 查询的结果
|
||||
---@return component component 提取的组件信息[包含多个组件]
|
||||
M.component = function(field)
|
||||
local component = {}
|
||||
local data = {
|
||||
{ field.word, 'TransWord' },
|
||||
}
|
||||
|
||||
if display.phnoetic and field.phonetic and field.phonetic ~= '' then
|
||||
table.insert(
|
||||
data,
|
||||
{ '[' .. field.phonetic .. ']', 'TransPhonetic' }
|
||||
)
|
||||
end
|
||||
|
||||
if display.collins and field.collins then
|
||||
table.insert(data, {
|
||||
icon.star:rep(field.collins)
|
||||
})
|
||||
end
|
||||
|
||||
if display.oxford and field.oxford then
|
||||
table.insert(data,
|
||||
{ field.oxford == 1 and icon.isOxford or icon.notOxford, }
|
||||
)
|
||||
end
|
||||
|
||||
component[1] = data
|
||||
return component
|
||||
end
|
||||
|
||||
return M
|
@ -1,23 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.component = function(field)
|
||||
if field.translation then
|
||||
local ref = {
|
||||
{ '中文翻译', 'TransRef' }
|
||||
}
|
||||
|
||||
local translations = {
|
||||
highlight = 'TransTranslation',
|
||||
indent = 4,
|
||||
emptyline = true,
|
||||
needformat = true,
|
||||
}
|
||||
for trans in vim.gsplit(field.translation, '\n', true) do
|
||||
table.insert(translations, trans)
|
||||
end
|
||||
|
||||
return { ref, translations }
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -1,123 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.conf = {
|
||||
style = {
|
||||
ui = {
|
||||
input = 'float',
|
||||
normal = 'cursor',
|
||||
select = 'cursor'
|
||||
},
|
||||
window = {
|
||||
cursor = {
|
||||
border = 'rounded',
|
||||
width = 50,
|
||||
height = 50,
|
||||
},
|
||||
float = {
|
||||
border = 'rounded',
|
||||
width = 0.9,
|
||||
height = 0.8,
|
||||
},
|
||||
-- NOTE :如果你想限制某个组件的行数,可以设置 (名称与order相同)
|
||||
-- Example:
|
||||
-- limit = {
|
||||
-- En = 1, -- 只显示第一行,(一般为最广泛的释义)
|
||||
-- },
|
||||
limit = nil,
|
||||
},
|
||||
},
|
||||
order = {
|
||||
offline = {
|
||||
'Title',
|
||||
'Tag',
|
||||
'Pos',
|
||||
'Exchange',
|
||||
'Translation',
|
||||
-- { 'Definition', max_size = 4 },
|
||||
},
|
||||
-- online = {
|
||||
-- -- TODO
|
||||
-- },
|
||||
},
|
||||
ui = {
|
||||
highlight = {
|
||||
TransWord = {
|
||||
fg = '#7ee787',
|
||||
bold = true,
|
||||
},
|
||||
TransPhonetic = {
|
||||
link = 'Linenr'
|
||||
},
|
||||
TransRef = {
|
||||
fg = '#75beff',
|
||||
bold = true,
|
||||
},
|
||||
TransTag = {
|
||||
fg = '#e5c07b',
|
||||
},
|
||||
TransExchange = {
|
||||
link = 'TransTag',
|
||||
},
|
||||
TransPos = {
|
||||
link = 'TransTag',
|
||||
},
|
||||
TransTranslation = {
|
||||
link = 'TransWord',
|
||||
},
|
||||
TransDefinition = {
|
||||
-- fg = '#bc8cff',
|
||||
link = 'Moremsg',
|
||||
},
|
||||
TransCursorWin = {
|
||||
link = 'Normal',
|
||||
},
|
||||
|
||||
TransCursorBorder = {
|
||||
link = 'FloatBorder',
|
||||
}
|
||||
},
|
||||
icon = {
|
||||
star = '⭐',
|
||||
isOxford = '✔',
|
||||
notOxford = ''
|
||||
},
|
||||
display = {
|
||||
phnoetic = true,
|
||||
collins = true,
|
||||
oxford = true,
|
||||
-- TODO
|
||||
-- history = false,
|
||||
},
|
||||
},
|
||||
base = {
|
||||
db_path = '$HOME/.vim/dict/ultimate.db',
|
||||
auto_close = true,
|
||||
engine = {
|
||||
-- TODO
|
||||
'offline',
|
||||
}
|
||||
},
|
||||
-- map = {
|
||||
-- -- TODO
|
||||
-- },
|
||||
-- history = {
|
||||
-- -- TOOD
|
||||
-- }
|
||||
|
||||
-- TODO add online translate engine
|
||||
-- online_search = {
|
||||
-- enable = false,
|
||||
-- engine = {},
|
||||
-- }
|
||||
|
||||
-- TODO register word
|
||||
}
|
||||
|
||||
-- INFO :加载的规则 [LuaRule]
|
||||
M.replace_rules = {
|
||||
'order.*',
|
||||
'ui.highlight.*',
|
||||
}
|
||||
|
||||
|
||||
return M
|
@ -1,60 +0,0 @@
|
||||
-- -@diagnostic disable: unused-local, unused-function, lowercase-global
|
||||
local M = {}
|
||||
|
||||
local replace_rules = require("Trans.conf.default").replace_rules
|
||||
|
||||
local star_format = [[
|
||||
local def, usr = default_conf.%s, user_conf.%s
|
||||
if def and usr then
|
||||
for k, v in pairs(usr) do
|
||||
def[k] = v
|
||||
usr[k] = nil
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
|
||||
local plain_format = [[
|
||||
default_conf.%s = user_conf.%s or default_conf.%s
|
||||
]]
|
||||
|
||||
local function pre_process()
|
||||
if replace_rules then
|
||||
for _, v in ipairs(replace_rules) do
|
||||
local start = v:find('.*', 1, true)
|
||||
local operation
|
||||
if start then
|
||||
-- 替换表内所有键
|
||||
v = v:sub(1, start - 1)
|
||||
-- print('v is :', v)
|
||||
operation = string.format(star_format, v, v)
|
||||
else
|
||||
operation = plain_format:format(v, v, v)
|
||||
end
|
||||
-- print(operation)
|
||||
pcall(loadstring(operation))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
M.load_conf = function(conf)
|
||||
user_conf = conf or {}
|
||||
default_conf = require("Trans.conf.default").conf
|
||||
if user_conf.style and user_conf.window then
|
||||
end
|
||||
|
||||
pre_process()
|
||||
M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
|
||||
local win = M.loaded_conf.style.window
|
||||
assert(win.float.height <= 1 and win.float.height > 0 and win.cursor.height > 1, win.cursor.width > 1)
|
||||
|
||||
win.float.width = math.floor(win.float.width * vim.o.columns)
|
||||
win.float.height = math.floor(win.float.height * (vim.o.lines - vim.o.cmdheight))
|
||||
|
||||
user_conf = nil
|
||||
default_conf = nil
|
||||
end
|
||||
|
||||
M.loaded_conf = nil
|
||||
|
||||
return M
|
21
lua/Trans/core/action.lua
Normal file
21
lua/Trans/core/action.lua
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
local function feedkey(mode, key)
|
||||
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, false, true), mode, false)
|
||||
end
|
||||
|
||||
|
||||
local M = {
|
||||
pageup = function (bufnr)
|
||||
return function ()
|
||||
vim.api.nvim_buf_call(bufnr, function ()
|
||||
-- TODO :
|
||||
end)
|
||||
end
|
||||
end,
|
||||
pagedown = function ()
|
||||
feedkey('n', '<C-d>')
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
return M
|
@ -1,294 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
|
||||
local opt = {
|
||||
method = 'select',
|
||||
view = 'cursor',
|
||||
}
|
||||
|
||||
M.Translate = function(opts)
|
||||
local res = get_query_res(opts.method)
|
||||
-- TODO <++>
|
||||
end
|
||||
|
||||
-- M.Translate_online = function ()
|
||||
-- -- TOOD
|
||||
-- end
|
||||
|
||||
|
||||
-- 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
|
||||
--
|
||||
-- -- 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('<cword>')
|
||||
-- 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
|
168
lua/Trans/core/content.lua
Normal file
168
lua/Trans/core/content.lua
Normal file
@ -0,0 +1,168 @@
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
||||
M.get_width = vim.fn.strdisplaywidth
|
||||
-- local get_width = vim.fn.strwidth
|
||||
-- local get_width = vim.api.nvim_strwidth
|
||||
|
||||
---@alias block table add_hl(key, hl_name)
|
||||
---返回分配的块状区域, e_col 设置为-1则为末尾
|
||||
---@param s_row integer 起始行
|
||||
---@param s_col integer 起始列
|
||||
---@param height integer 行数
|
||||
---@param width integer 块的宽度
|
||||
---@return block
|
||||
function M:alloc_block(s_row, s_col, height, width)
|
||||
-- -1为到行尾
|
||||
width = width == -1 and self.width or width
|
||||
local e_col = s_col + width
|
||||
|
||||
local block = {
|
||||
add_hl = function(key, hl_name)
|
||||
table.insert(self.highlight[s_row + key], {
|
||||
name = hl_name,
|
||||
_start = s_col,
|
||||
_end = e_col,
|
||||
})
|
||||
end
|
||||
}
|
||||
|
||||
return setmetatable(block, {
|
||||
-- 访问该表的操作, 映射成lines
|
||||
__index = function(_, key)
|
||||
assert(0 < key and key <= height)
|
||||
--- FIXME : Unicode stirng sub
|
||||
return self.lines[s_row + key]:sub(s_col, e_col)
|
||||
end,
|
||||
|
||||
__newindex = function(_, key, value)
|
||||
assert(0 < key and key <= height)
|
||||
local wid = self.get_width(value)
|
||||
if wid > width then
|
||||
error('check out the str width: Max ->' .. self.width .. ' str ->' .. wid)
|
||||
else
|
||||
value = value .. (' '):rep(width - wid)
|
||||
end
|
||||
|
||||
local line = s_row + key - 1
|
||||
self.lines[line] = self.lines[line]:sub(1, s_col - 1) .. value .. self.lines[line]:sub(e_col + 1)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function M:alloc_items()
|
||||
local items = {}
|
||||
local len = 0
|
||||
local size = 0
|
||||
return {
|
||||
add_item = function(item, highlight)
|
||||
size = size + 1
|
||||
local wid = self.get_width(item)
|
||||
items[size] = { item, highlight }
|
||||
len = len + wid
|
||||
end,
|
||||
|
||||
load = function()
|
||||
self.len = self.len + 1
|
||||
local space = math.floor((self.width - len) / (size - 1))
|
||||
assert(space > 0)
|
||||
local interval = (' '):rep(space)
|
||||
local value = ''
|
||||
local function load_item(index)
|
||||
if items[index][2] then
|
||||
local _start = #value
|
||||
local _end = _start + #items[index][1]
|
||||
table.insert(self.highlights[self.len], {
|
||||
name = items[index][2],
|
||||
_start = _start,
|
||||
_end = _end
|
||||
})
|
||||
end
|
||||
value = value .. items[index][1]
|
||||
end
|
||||
|
||||
load_item(1)
|
||||
for i = 2, size do
|
||||
value = value .. interval
|
||||
load_item(i)
|
||||
end
|
||||
|
||||
self.lines[self.len] = value
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
function M:alloc_text()
|
||||
local value = ''
|
||||
return {
|
||||
add_text = function(text, highlight)
|
||||
if highlight then
|
||||
local _start = #value
|
||||
local _end = _start + #text
|
||||
table.insert(self.highlights[self.len + 1], {
|
||||
name = highlight,
|
||||
_start = _start,
|
||||
_end = _end,
|
||||
})
|
||||
end
|
||||
value = value .. text
|
||||
end,
|
||||
load = function ()
|
||||
self.len = self.len + 1
|
||||
self.lines[self.len] = value
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function M:addline(text, highlight)
|
||||
self.len = self.len + 1
|
||||
if highlight then
|
||||
table.insert(self.highlights[self.len], {
|
||||
name = highlight,
|
||||
_start = 0,
|
||||
_end = -1
|
||||
})
|
||||
end
|
||||
self.lines[self.len] = text
|
||||
end
|
||||
|
||||
-- 窗口宽度
|
||||
function M:new(width)
|
||||
vim.validate {
|
||||
width = { width, 'n' }
|
||||
}
|
||||
local default = (' '):rep(width) -- default value is empty line
|
||||
local new_content = {
|
||||
width = width,
|
||||
len = 0,
|
||||
highlights = setmetatable({}, { -- always has default value
|
||||
__index = function(tbl, key)
|
||||
tbl[key] = {}
|
||||
return tbl[key]
|
||||
end
|
||||
}),
|
||||
|
||||
}
|
||||
|
||||
new_content.lines = setmetatable({}, {
|
||||
__index = function(tbl, key)
|
||||
tbl[key] = default
|
||||
return tbl[key]
|
||||
end,
|
||||
|
||||
__newindex = function(tbl, key, value)
|
||||
if value then
|
||||
for _ = new_content.len + 1, key - 1 do
|
||||
rawset(tbl, key, '')
|
||||
end
|
||||
|
||||
rawset(tbl, key, value)
|
||||
new_content.len = key
|
||||
end
|
||||
end
|
||||
})
|
||||
return setmetatable(new_content, self)
|
||||
end
|
||||
|
||||
return M
|
148
lua/Trans/core/handler.lua
Normal file
148
lua/Trans/core/handler.lua
Normal file
@ -0,0 +1,148 @@
|
||||
local M = {}
|
||||
local icon = require('Trans').conf.icon
|
||||
|
||||
-- local components = {
|
||||
-- 'title',
|
||||
-- 'tag',
|
||||
-- 'pos',
|
||||
-- 'exchange',
|
||||
-- 'translation',
|
||||
-- 'definition'
|
||||
-- }
|
||||
|
||||
local tag_map = {
|
||||
zk = '中考',
|
||||
gk = '高考',
|
||||
ky = '考研',
|
||||
cet4 = '四级',
|
||||
cet6 = '六级',
|
||||
ielts = '雅思',
|
||||
toefl = '托福',
|
||||
gre = 'gre ',
|
||||
}
|
||||
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 exchange_map = {
|
||||
['p'] = '过去式 ',
|
||||
['d'] = '过去分词 ',
|
||||
['i'] = '现在分词 ',
|
||||
['r'] = '比较级 ',
|
||||
['t'] = '最高级 ',
|
||||
['s'] = '复数 ',
|
||||
['0'] = '原型 ',
|
||||
['1'] = '类别 ',
|
||||
['3'] = '第三人称单数',
|
||||
['f'] = '第三人称单数',
|
||||
}
|
||||
|
||||
local function exist(res)
|
||||
return res and res ~= ''
|
||||
end
|
||||
|
||||
local function expl(c, text)
|
||||
local t = c:alloc_text()
|
||||
t.add_text('', 'TransTitleRound')
|
||||
t.add_text(text, 'TransTitle')
|
||||
t.add_text('', 'TransTitleRound')
|
||||
t.load()
|
||||
end
|
||||
|
||||
local indent = ' '
|
||||
|
||||
M.hover = {
|
||||
title = function(result, content)
|
||||
local line = content:alloc_items()
|
||||
line.add_item(result.word, 'TransWord')
|
||||
local pho = ('[' .. (exist(result.phonetic) and result.phonetic or icon.notfound) .. ']')
|
||||
-- line.add_item(pho, 'TransPhonetic', #pho)
|
||||
line.add_item(pho, 'TransPhonetic')
|
||||
line.add_item((exist(result.collins) and icon.star:rep(result.collins) or icon.notfound), 'TransCollins')
|
||||
line.add_item((result.oxford == 1 and icon.yes or icon.no))
|
||||
line.load()
|
||||
end,
|
||||
|
||||
tag = function(result, content)
|
||||
if exist(result.tag) then
|
||||
expl(content, '标签')
|
||||
|
||||
local tags = vim.tbl_map(function(tag)
|
||||
return tag_map[tag]
|
||||
end, vim.split(result.tag, ' ', { plain = true, trimempry = true }))
|
||||
|
||||
local size = #tags
|
||||
local i = 1
|
||||
while i <= size do
|
||||
content:addline(indent .. tags[i] .. ' ' .. (tags[i + 1] or '') .. ' ' .. (tags[i + 2] or ''),
|
||||
'TransTag')
|
||||
i = i + 3
|
||||
end
|
||||
content:addline('')
|
||||
end
|
||||
end,
|
||||
|
||||
pos = function(result, content)
|
||||
if exist(result.pos) then
|
||||
expl(content, '词性')
|
||||
vim.tbl_map(function(pos)
|
||||
content:addline(indent .. pos_map[pos:sub(1, 1)] .. pos:sub(3) .. '%', 'TransPos')
|
||||
end, vim.split(result.pos, '/', { plain = true, trimempry = true }))
|
||||
|
||||
content:addline('')
|
||||
end
|
||||
end,
|
||||
|
||||
exchange = function(result, content)
|
||||
if exist(result.exchange) then
|
||||
expl(content, '词形变化')
|
||||
|
||||
vim.tbl_map(function(exc)
|
||||
content:addline(indent .. exchange_map[exc:sub(1, 1)] .. ' ' .. exc:sub(3), 'TransExchange')
|
||||
end, vim.split(result.exchange, '/', { plain = true, trimempry = true }))
|
||||
|
||||
content:addline('')
|
||||
end
|
||||
end,
|
||||
|
||||
translation = function(result, content)
|
||||
expl(content, '中文翻译')
|
||||
|
||||
vim.tbl_map(function(trs)
|
||||
content:addline(indent .. trs, 'TransTranslation')
|
||||
end, vim.split(result.translation, '\n', { plain = true, trimempry = true }))
|
||||
|
||||
content:addline('')
|
||||
end,
|
||||
|
||||
|
||||
definition = function(result, content)
|
||||
if exist(result.definition) then
|
||||
expl(content, '英文注释')
|
||||
|
||||
vim.tbl_map(function(def)
|
||||
content:addline(def, 'TransDefinition')
|
||||
end, vim.split(indent .. result.definition, '\n', { plain = true, trimempry = true }))
|
||||
|
||||
content:addline('')
|
||||
end
|
||||
end,
|
||||
failed = function(content)
|
||||
content:addline(icon.notfound .. indent .. '没有找到相关的翻译')
|
||||
end,
|
||||
}
|
||||
|
||||
return M
|
@ -1,7 +1,54 @@
|
||||
local M = {}
|
||||
local conf = require('Trans').conf
|
||||
local api = require('Trans.api')
|
||||
local win = require('Trans.core.window')
|
||||
local handler = require('Trans.core.handler')
|
||||
local c = require('Trans.core.content')
|
||||
|
||||
|
||||
local function get_select()
|
||||
local s_start = vim.fn.getpos("v")
|
||||
local s_end = vim.fn.getpos(".")
|
||||
local n_lines = math.abs(s_end[2] - s_start[2]) + 1
|
||||
local lines = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)
|
||||
lines[1] = string.sub(lines[1], s_start[3], -1)
|
||||
if n_lines == 1 then
|
||||
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3] - s_start[3] + 1)
|
||||
else
|
||||
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3])
|
||||
end
|
||||
return table.concat(lines, '')
|
||||
end
|
||||
|
||||
M.translate = function(method, view)
|
||||
method = method or vim.api.nvim_get_mode().mode
|
||||
view = view or conf.view[method]
|
||||
local word
|
||||
if method == 'input' then
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
|
||||
elseif method == 'n' then
|
||||
word = vim.fn.expand('<cword>')
|
||||
elseif method == 'v' then
|
||||
word = get_select()
|
||||
end
|
||||
|
||||
|
||||
win.init(view)
|
||||
local result = api.query('offline', word)
|
||||
local content = c:new(win.width)
|
||||
local hd = handler[view]
|
||||
|
||||
if result then
|
||||
for i = 1, #conf.order do
|
||||
hd[conf.order[i]](result, content)
|
||||
end
|
||||
|
||||
else
|
||||
hd.failed(content)
|
||||
end
|
||||
win.draw(content)
|
||||
end
|
||||
|
||||
M.process = require('Trans.core.process')
|
||||
M.query = require('Trans.core.query')
|
||||
-- M.show_win = require('Trans.core.show_win')
|
||||
|
||||
return M
|
||||
|
@ -1,170 +0,0 @@
|
||||
local type_check = vim.validate
|
||||
|
||||
-- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
|
||||
-- 为了解决中文字符在lua的长度和neovim显示不一致的问题
|
||||
local get_width = vim.fn.strdisplaywidth
|
||||
|
||||
local function format(win_width, items)
|
||||
local size = #items
|
||||
local tot_width = 0
|
||||
|
||||
if items.indent then
|
||||
win_width = win_width - items.indent
|
||||
end
|
||||
|
||||
for i = 1, size do
|
||||
if type(items[i]) == 'string' then
|
||||
items[i] = { items[i] }
|
||||
end
|
||||
tot_width = tot_width + #items[i][1] + 4
|
||||
end
|
||||
|
||||
|
||||
-- 判断宽度是否超过最大宽度
|
||||
if tot_width > win_width + 4 then
|
||||
-- 放不下则需要分成多行
|
||||
local lines = {}
|
||||
|
||||
-- 行内字符串按照宽度排序
|
||||
table.sort(items, function(a, b)
|
||||
return #a[1] > #b[1]
|
||||
end)
|
||||
|
||||
local cols = 1
|
||||
win_width = win_width - #items[1][1]
|
||||
|
||||
while win_width > 0 and cols < size do
|
||||
cols = cols + 1
|
||||
win_width = win_width - #items[cols][1] + 4
|
||||
end
|
||||
if cols > 1 then
|
||||
cols = cols - 1
|
||||
end
|
||||
|
||||
if cols == 1 then -- 只能放在一行时就对齐了
|
||||
for i = size, 1, -1 do
|
||||
lines[i] = {
|
||||
items[i][1],
|
||||
highlight = items.highlight,
|
||||
indent = items.indent,
|
||||
}
|
||||
end
|
||||
return lines, true
|
||||
end
|
||||
|
||||
|
||||
local rows = math.ceil(size / cols)
|
||||
local rest = size % cols
|
||||
if rest == 0 then
|
||||
rest = cols
|
||||
end
|
||||
|
||||
local max_width = get_width(items[1][1])
|
||||
local index = 1 -- 当前操作的字符串下标
|
||||
for i = rows, 1, -1 do -- 当前操作的行号
|
||||
lines[i] = {
|
||||
highlight = items.highlight,
|
||||
indent = items.indent,
|
||||
}
|
||||
|
||||
local item = items[index]
|
||||
-- if not item then
|
||||
-- error('item nil ' .. tostring(index) .. ' rows:' .. tostring(rows) .. vim.inspect(items) )
|
||||
-- end
|
||||
|
||||
item[1] = item[1] .. (' '):rep(max_width - get_width(item[1]))
|
||||
lines[i][1] = items[index]
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
|
||||
for col = 2, cols do
|
||||
max_width = get_width(items[index][1])
|
||||
local _end = col > rest and rows - 1 or rows
|
||||
|
||||
for i = _end, 1, -1 do
|
||||
local item = items[index]
|
||||
item[1] = item[1] .. (' '):rep(max_width - get_width(item[1]))
|
||||
|
||||
|
||||
lines[i][col] = item
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
|
||||
return lines, true
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
local function process(opts)
|
||||
type_check {
|
||||
opts = { opts, 'table' },
|
||||
['opts.field'] = { opts.field, 'table', true },
|
||||
['opts.order'] = { opts.order, 'table' },
|
||||
['opts.win'] = { opts.win, 'table' },
|
||||
['opts.engine'] = { opts.engine, 'table' },
|
||||
}
|
||||
|
||||
if opts.field == nil then
|
||||
local lines = { '⚠️ 本地没有找到相关释义' }
|
||||
vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_win_set_height(opts.winid, 1)
|
||||
vim.api.nvim_win_set_width(opts.winid, get_width(lines[1]))
|
||||
else
|
||||
local content = require('Trans.component.content'):new(opts)
|
||||
for _, v in ipairs(opts.order) do
|
||||
local component
|
||||
if type(v) == 'table' then
|
||||
component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v[1]).component(opts.field
|
||||
, v.max_size)
|
||||
else
|
||||
component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v).component(opts.field)
|
||||
end
|
||||
if component then
|
||||
for _, items in ipairs(component) do
|
||||
|
||||
if items.needformat then
|
||||
local formatted_items, split = format(opts.win.width, items)
|
||||
if split then
|
||||
for _, itms in ipairs(formatted_items) do
|
||||
content:insert(itms)
|
||||
end
|
||||
else
|
||||
content:insert(formatted_items)
|
||||
end
|
||||
else
|
||||
content:insert(items)
|
||||
end
|
||||
|
||||
if items.emptyline then
|
||||
content:insert({ '' })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
content:attach()
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_option(opts.bufnr, 'modifiable', false)
|
||||
vim.api.nvim_buf_set_option(opts.bufnr, 'filetype', 'Trans')
|
||||
|
||||
vim.api.nvim_win_set_option(opts.winid, 'wrap', true)
|
||||
vim.api.nvim_win_set_option(opts.winid, 'winhl', 'Normal:TransCursorWin,FloatBorder:TransCursorBorder')
|
||||
if opts.win.style == 'cursor' then
|
||||
vim.api.nvim_create_autocmd(
|
||||
{ 'InsertEnter', 'CursorMoved', 'BufLeave', }, {
|
||||
buffer = 0,
|
||||
once = true,
|
||||
callback = function()
|
||||
if vim.api.nvim_win_is_valid(opts.winid) then
|
||||
vim.api.nvim_win_close(opts.winid, true)
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return process
|
@ -1,43 +0,0 @@
|
||||
local type_check = vim.validate
|
||||
local query = require("Trans.api").query
|
||||
|
||||
local function get_select()
|
||||
local s_start = vim.fn.getpos("v")
|
||||
local s_end = vim.fn.getpos(".")
|
||||
local n_lines = math.abs(s_end[2] - s_start[2]) + 1
|
||||
local lines = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)
|
||||
lines[1] = string.sub(lines[1], s_start[3], -1)
|
||||
if n_lines == 1 then
|
||||
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3] - s_start[3] + 1)
|
||||
else
|
||||
lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3])
|
||||
end
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
local query_wrapper = function(opts)
|
||||
type_check {
|
||||
opts = { opts, 'table' },
|
||||
['opts.method'] = { opts.method, 'string' },
|
||||
}
|
||||
|
||||
local word = ''
|
||||
|
||||
if opts.method == 'input' then
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
|
||||
|
||||
elseif opts.method == 'n' then
|
||||
word = vim.fn.expand('<cword>')
|
||||
|
||||
elseif opts.method == 'v' then
|
||||
word = get_select()
|
||||
-- TODO : other method
|
||||
else
|
||||
error('invalid method' .. opts.method)
|
||||
end
|
||||
|
||||
return query(word)
|
||||
end
|
||||
|
||||
return query_wrapper
|
@ -1,113 +0,0 @@
|
||||
-- Default conf
|
||||
local conf = require("Trans.conf.loader").loaded_conf
|
||||
local core = require("Trans.core")
|
||||
|
||||
|
||||
local function get_opts(opts)
|
||||
local default_conf = {
|
||||
method = vim.api.nvim_get_mode().mode,
|
||||
engine = {
|
||||
'offline',
|
||||
-- TODO : other engine
|
||||
},
|
||||
win = {
|
||||
style = 'cursor',
|
||||
width = conf.style.window.cursor.width,
|
||||
height = conf.style.window.cursor.height
|
||||
},
|
||||
}
|
||||
|
||||
if type(opts.engine) == 'string' then
|
||||
opts.engine = { opts.engine }
|
||||
end
|
||||
|
||||
|
||||
if opts.win then
|
||||
local width, height = opts.win.width, opts.win.height
|
||||
if width and width > 0 and width <= 1 then
|
||||
opts.win.width = math.floor(vim.o.columns * width)
|
||||
end
|
||||
|
||||
if height and height > 0 and height <= 1 then
|
||||
opts.win.height = math.floor(vim.o.lines * opts.win.height)
|
||||
end
|
||||
end
|
||||
|
||||
return vim.tbl_extend('force', default_conf, opts)
|
||||
end
|
||||
|
||||
|
||||
-- EXAMPLE :
|
||||
-- require('Trans').translate({
|
||||
-- method = 'input', -- 不填则自动判断mode获取查询的单词
|
||||
-- engine = { -- 异步查询所有的引擎, 按照列表
|
||||
-- 'offline',
|
||||
-- 'youdao',
|
||||
-- 'baidu'
|
||||
-- },
|
||||
-- -- win = 'cursor'
|
||||
-- win = {
|
||||
-- style = 'cursor',
|
||||
-- height = 50,
|
||||
-- width = 30,
|
||||
-- }
|
||||
-- })
|
||||
|
||||
|
||||
|
||||
local function create_win(win)
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
|
||||
local is_float = win.style == 'float'
|
||||
|
||||
local win_opts = {
|
||||
relative = is_float and 'editor' or 'cursor',
|
||||
width = win.width,
|
||||
height = win.height,
|
||||
style = 'minimal',
|
||||
border = conf.style.window[win.style].border,
|
||||
title = 'Trans',
|
||||
title_pos = 'center',
|
||||
focusable = true,
|
||||
zindex = 100,
|
||||
}
|
||||
|
||||
if is_float then
|
||||
win_opts.row = math.floor((vim.o.lines - win_opts.height - vim.o.cmdheight) / 2)
|
||||
win_opts.col = math.floor((vim.o.columns - win_opts.width) / 2)
|
||||
else
|
||||
win_opts.row = 2
|
||||
win_opts.col = 2
|
||||
end
|
||||
|
||||
|
||||
local winid = vim.api.nvim_open_win(bufnr, is_float, win_opts)
|
||||
return bufnr, winid
|
||||
end
|
||||
|
||||
|
||||
local function translate(opts)
|
||||
vim.validate {
|
||||
opts = { opts, 'table', true }
|
||||
}
|
||||
|
||||
--- TODO : 异步请求
|
||||
-- NOTE : 这里只处理了本地数据库查询
|
||||
opts = get_opts(opts or {})
|
||||
local field = core.query(opts)
|
||||
|
||||
local bufnr, winid = create_win(opts.win)
|
||||
|
||||
local proc_opts = {
|
||||
bufnr = bufnr,
|
||||
winid = winid,
|
||||
win = opts.win,
|
||||
field = field,
|
||||
order = conf.order['offline'],
|
||||
engine = { 'offline' },
|
||||
}
|
||||
|
||||
core.process(proc_opts)
|
||||
end
|
||||
|
||||
return translate
|
114
lua/Trans/core/window.lua
Normal file
114
lua/Trans/core/window.lua
Normal file
@ -0,0 +1,114 @@
|
||||
local M = {}
|
||||
local api = vim.api
|
||||
local conf = require('Trans').conf
|
||||
local action = require('Trans.core.action')
|
||||
|
||||
M.id = 0
|
||||
M.bufnr = 0
|
||||
M.ns = api.nvim_create_namespace('Trans')
|
||||
|
||||
|
||||
function M.init(view)
|
||||
vim.validate {
|
||||
view = { view, 's' }
|
||||
}
|
||||
|
||||
M.view = view
|
||||
M.float = view == 'float'
|
||||
M.height = conf.window[view].height
|
||||
M.width = conf.window[view].width
|
||||
|
||||
local opts = {
|
||||
relative = M.float and 'editor' or 'cursor',
|
||||
width = M.width,
|
||||
height = M.height,
|
||||
style = 'minimal',
|
||||
border = conf.window.border,
|
||||
title = {
|
||||
{'', 'TransTitleRound'},
|
||||
{'Trans', 'TransTitle'},
|
||||
{'', 'TransTitleRound'},
|
||||
},
|
||||
title_pos = 'center',
|
||||
focusable = true,
|
||||
zindex = 100,
|
||||
}
|
||||
|
||||
if M.float then
|
||||
opts.row = math.floor((vim.o.lines - M.height) / 2)
|
||||
opts.col = math.floor((vim.o.columns - M.width) / 2)
|
||||
else
|
||||
opts.row = 2
|
||||
opts.col = 2
|
||||
end
|
||||
|
||||
M.bufnr = api.nvim_create_buf(false, true)
|
||||
M.id = api.nvim_open_win(M.bufnr, M.float, opts)
|
||||
end
|
||||
|
||||
M.draw = function(content)
|
||||
api.nvim_buf_set_lines(M.bufnr, 0, -1, false, content.lines)
|
||||
|
||||
if content.highlights then
|
||||
for l, _hl in pairs(content.highlights) do
|
||||
for _, hl in ipairs(_hl) do
|
||||
api.nvim_buf_add_highlight(M.bufnr, M.ns, hl.name, l - 1, hl._start, hl._end) -- zero index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local len = #content.lines
|
||||
if M.height > len then
|
||||
api.nvim_win_set_height(M.id, len)
|
||||
end
|
||||
if len == 1 then
|
||||
api.nvim_win_set_width(M.id, content.get_width(content.lines[1]))
|
||||
end
|
||||
|
||||
|
||||
api.nvim_buf_set_option(M.bufnr, 'modifiable', false)
|
||||
api.nvim_buf_set_option(M.bufnr, 'filetype', 'Trans')
|
||||
api.nvim_win_set_option(M.id, 'wrap', not M.float)
|
||||
api.nvim_win_set_option(M.id, 'winhl', ('Normal:Trans%sWin,FloatBorder:Trans%sBorder'):format(M.view, M.view))
|
||||
|
||||
if M.float then
|
||||
vim.keymap.set('n', 'q', function()
|
||||
if api.nvim_win_is_valid(M.id) then
|
||||
api.nvim_win_close(M.id, true)
|
||||
end
|
||||
end, { buffer = M.bufnr, silent = true })
|
||||
|
||||
else
|
||||
-- TODO : set keymaps for window
|
||||
M.auto_close()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
M.auto_close = function()
|
||||
api.nvim_create_autocmd(
|
||||
{ 'InsertEnter', 'CursorMoved', 'BufLeave', }, {
|
||||
buffer = 0,
|
||||
once = true,
|
||||
callback = function()
|
||||
if api.nvim_win_is_valid(M.id) then
|
||||
api.nvim_win_close(M.id, true)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- M.load_keymap = function (once)
|
||||
-- local keymap = conf.keymap[M.view]
|
||||
-- local function warp(func)
|
||||
-- return func or function ()
|
||||
-- vim.api.nvim_get_keymap(' th')
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- end
|
||||
|
||||
|
||||
return M
|
@ -1,12 +1,93 @@
|
||||
local M = {}
|
||||
|
||||
M.conf = {
|
||||
view = {
|
||||
input = 'hover',
|
||||
n = 'hover',
|
||||
v = 'hover',
|
||||
},
|
||||
window = {
|
||||
border = 'rounded',
|
||||
hover = {
|
||||
width = 36,
|
||||
height = 23,
|
||||
},
|
||||
float = {
|
||||
width = 0.8,
|
||||
height = 0.8,
|
||||
},
|
||||
},
|
||||
|
||||
order = {
|
||||
-- offline = {
|
||||
'title',
|
||||
'tag',
|
||||
'pos',
|
||||
'exchange',
|
||||
'translation',
|
||||
-- NOTE :如果你想限制某个组件的行数,可以设置max_size
|
||||
-- { 'Definition', max_size = 4 },
|
||||
'definition',
|
||||
-- },
|
||||
-- online = {
|
||||
-- -- TODO
|
||||
-- },
|
||||
},
|
||||
icon = {
|
||||
star = '',
|
||||
notfound = '',
|
||||
yes = '',
|
||||
no = ''
|
||||
-- star = '⭐',
|
||||
-- notfound = '❔',
|
||||
-- yes = '✔️',
|
||||
-- no = '❌'
|
||||
},
|
||||
db_path = '$HOME/.vim/dict/ultimate.db',
|
||||
-- TODO :
|
||||
-- engine = {
|
||||
-- -- TODO
|
||||
-- 'offline',
|
||||
-- }
|
||||
map = {
|
||||
-- TODO
|
||||
hover = {
|
||||
pageup = '<C-u>',
|
||||
pagedown = '<C-d>',
|
||||
},
|
||||
},
|
||||
-- history = {
|
||||
-- -- TOOD
|
||||
-- }
|
||||
|
||||
-- TODO add online translate engine
|
||||
-- online_search = {
|
||||
-- enable = false,
|
||||
-- engine = {},
|
||||
-- }
|
||||
|
||||
-- TODO register word
|
||||
}
|
||||
|
||||
|
||||
M.setup = function(opts)
|
||||
require('Trans.conf.loader').load_conf(opts)
|
||||
if opts then
|
||||
M.conf = vim.tbl_deep_extend('force', M.conf, opts)
|
||||
end
|
||||
local window = M.conf.window
|
||||
assert(window.hover.width > 1 and window.hover.height > 1)
|
||||
assert(0 < window.float.width and window.float.width <= 1)
|
||||
assert(0 < window.float.height and window.float.height <= 1)
|
||||
|
||||
window.float.height = math.floor((vim.o.lines - vim.o.cmdheight - 1) * window.float.height)
|
||||
window.float.width = math.floor(vim.o.columns * window.float.width)
|
||||
|
||||
-- TODO : replace the height and width for float options
|
||||
M.translate = require('Trans.core').translate
|
||||
require("Trans.setup")
|
||||
M.translate = require('Trans.core.translate')
|
||||
end
|
||||
|
||||
M.translate = nil
|
||||
M.augroup = vim.api.nvim_create_augroup('Trans', {clear = true})
|
||||
|
||||
M.augroup = vim.api.nvim_create_augroup('Trans', { clear = true })
|
||||
|
||||
return M
|
||||
|
@ -2,24 +2,64 @@ if vim.fn.executable('sqlite3') ~= 1 then
|
||||
error('Please check out sqlite3')
|
||||
end
|
||||
|
||||
vim.api.nvim_create_user_command('Translate', function ()
|
||||
vim.api.nvim_create_user_command('Translate', function()
|
||||
require("Trans").translate()
|
||||
end, {
|
||||
desc = ' 单词翻译',
|
||||
})
|
||||
|
||||
vim.api.nvim_create_user_command('TranslateInput', function ()
|
||||
require("Trans").translate {
|
||||
method = 'input',
|
||||
}
|
||||
end, {desc = ' 搜索翻译'})
|
||||
vim.api.nvim_create_user_command('TranslateInput', function()
|
||||
require("Trans").translate('input')
|
||||
end, { desc = ' 搜索翻译' })
|
||||
|
||||
|
||||
local highlights = {
|
||||
TransWord = {
|
||||
fg = '#7ee787',
|
||||
bold = true,
|
||||
},
|
||||
TransPhonetic = {
|
||||
link = 'Linenr'
|
||||
},
|
||||
TransTitle = {
|
||||
fg = '#0f0f15',
|
||||
bg = '#75beff',
|
||||
},
|
||||
TransTitleRound = {
|
||||
fg = '#75beff',
|
||||
},
|
||||
TransTag = {
|
||||
fg = '#e5c07b',
|
||||
},
|
||||
TransExchange = {
|
||||
link = 'TransTag',
|
||||
},
|
||||
TransPos = {
|
||||
link = 'TransTag',
|
||||
},
|
||||
TransTranslation = {
|
||||
link = 'TransWord',
|
||||
},
|
||||
TransDefinition = {
|
||||
link = 'Moremsg',
|
||||
},
|
||||
TransHoverWin = {
|
||||
link = 'Normal',
|
||||
},
|
||||
TransHoverBorder = {
|
||||
link = 'FloatBorder',
|
||||
},
|
||||
TransCollins = {
|
||||
fg = '#faf743',
|
||||
bold = true,
|
||||
},
|
||||
}
|
||||
|
||||
-- TODO
|
||||
-- vim.api.nvim_create_user_command('TranslateHistory', require("Trans.core").query_input, {
|
||||
-- desc = '翻译输入的单词',
|
||||
-- })
|
||||
|
||||
local highlights = require("Trans.conf.loader").loaded_conf.ui.highlight
|
||||
for highlight, opt in pairs(highlights) do
|
||||
vim.api.nvim_set_hl(0, highlight, opt)
|
||||
end
|
||||
|
@ -1,186 +1,188 @@
|
||||
local M = {}
|
||||
-- local type_check = require("Trans.util.debug").type_check
|
||||
|
||||
|
||||
-- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
|
||||
-- 为了解决中文字符在lua的长度和neovim显示不一致的问题
|
||||
function string:width()
|
||||
return vim.fn.strdisplaywidth(self)
|
||||
end
|
||||
|
||||
-- 各种风格的基础宽度
|
||||
local style_width = {
|
||||
-- float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
|
||||
cursor = 60,
|
||||
}
|
||||
local s_to_b = true -- 从小到大排列
|
||||
|
||||
local m_fields -- 待格式化的字段
|
||||
local m_indent -- 每行的行首缩进
|
||||
local m_tot_width -- 所有字段加起来的长度(不包括缩进和间隔)
|
||||
local m_interval -- 每个字段的间隔
|
||||
local m_win_width -- 需要被格式化窗口的高度
|
||||
local m_item_width -- 每个字段的宽度
|
||||
local m_size
|
||||
|
||||
local function caculate_format()
|
||||
local width = m_win_width - m_item_width[1]
|
||||
local cols = 0
|
||||
for i = 2, #m_fields do
|
||||
width = width - m_item_width[i] - m_interval
|
||||
if width < 0 then
|
||||
cols = i - 1
|
||||
break
|
||||
else
|
||||
cols = i
|
||||
end
|
||||
end
|
||||
|
||||
return math.ceil(#m_fields / cols), cols
|
||||
end
|
||||
|
||||
local function format_to_line()
|
||||
local line = m_fields[1]
|
||||
if m_size == 1 then
|
||||
--- Center Align
|
||||
local space = math.floor((m_win_width - m_item_width[1]) / 2)
|
||||
line = (' '):rep(space) .. line
|
||||
else
|
||||
local space = math.floor((m_win_width - m_tot_width) / m_size - 1)
|
||||
for i = 2, m_size do
|
||||
line = line .. (' '):rep(space) .. m_fields[i]
|
||||
end
|
||||
end
|
||||
return line
|
||||
end
|
||||
|
||||
|
||||
local function sort_tables()
|
||||
table.sort(m_item_width, function (a, b)
|
||||
return a > b
|
||||
end)
|
||||
|
||||
table.sort(m_fields, function (a, b)
|
||||
return a:width() > b:width()
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local function format_to_multilines()
|
||||
local lines = {}
|
||||
sort_tables()
|
||||
|
||||
--- NOTE : 计算应该格式化成多少行和列
|
||||
local rows, cols = caculate_format()
|
||||
local rest = #m_fields % cols
|
||||
if rest == 0 then
|
||||
rest = cols
|
||||
end
|
||||
|
||||
local s_width = m_item_width[1] -- 列中最宽的字符串宽度
|
||||
-- NOTE : 第一列不需要加空格
|
||||
for i = 1, rows do
|
||||
local idx = s_to_b and rows - i + 1 or i
|
||||
local space = (' '):rep(s_width - m_item_width[i])
|
||||
lines[idx] = m_fields[i] .. space -- NOTE 由大到小
|
||||
end
|
||||
|
||||
local index = rows + 1 -- 最宽字符的下标
|
||||
local interval = (' '):rep(m_interval) -- 每个字符串间的间隙
|
||||
|
||||
for j = 2, cols do -- 以列为单位遍历
|
||||
s_width = m_item_width[index]
|
||||
local stop = (j > rest and rows - 1 or rows)
|
||||
for i = 1, stop do
|
||||
local idx = s_to_b and stop - i + 1 or i -- 当前操作的行数
|
||||
local item = index + i - 1 -- 当前操作的字段数
|
||||
local space = (' '):rep(s_width - m_item_width[item]) -- 对齐空格
|
||||
|
||||
lines[idx] = lines[idx] .. interval .. m_fields[item] .. space -- NOTE 从大到小
|
||||
end
|
||||
index = index + stop -- 更新最宽字符的下标
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
|
||||
local function get_formatted_lines()
|
||||
local lines = {}
|
||||
-- NOTE : 判断能否格式化成一行
|
||||
local line_size = m_tot_width + (#m_fields * m_interval)
|
||||
if line_size > m_win_width then
|
||||
lines = format_to_multilines()
|
||||
else
|
||||
lines[1] = format_to_line()
|
||||
end
|
||||
|
||||
-- NOTE :进行缩进
|
||||
if m_indent > 0 then
|
||||
for i, v in ipairs(lines) do
|
||||
lines[i] = (' '):rep(m_indent) .. v
|
||||
end
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
---将组件格式化成相应的vim支持的lines格式
|
||||
---@param style string 窗口的风格
|
||||
---@param fields string[] 需要格式化的字段
|
||||
---@param indent? number 缩进的长度
|
||||
---@return string[] lines 便于vim.api.nvim_buf_set_lines
|
||||
M.to_lines = function(style, fields, indent)
|
||||
|
||||
local length = 0
|
||||
local width = 0
|
||||
local item_size = {}
|
||||
for i, v in ipairs(fields) do
|
||||
width = v:width()
|
||||
item_size[i] = width
|
||||
length = length + width
|
||||
end
|
||||
|
||||
m_indent = indent or 0
|
||||
m_win_width = style_width[style] - m_indent
|
||||
m_fields = fields
|
||||
m_tot_width = length
|
||||
m_item_width = item_size
|
||||
m_interval = m_win_width > 50 and 6 or 4
|
||||
m_size = #fields
|
||||
|
||||
return get_formatted_lines()
|
||||
end
|
||||
|
||||
local test = {
|
||||
'isjlk测试dj',
|
||||
'测试一下..',
|
||||
}
|
||||
|
||||
local lines = M.to_lines('cursor', test)
|
||||
|
||||
-- print('===========================================')
|
||||
-- local M = {}
|
||||
-- -- local type_check = require("Trans.util.debug").type_check
|
||||
--
|
||||
--
|
||||
-- -- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
|
||||
-- -- 为了解决中文字符在lua的长度和neovim显示不一致的问题
|
||||
-- function string:width()
|
||||
-- return vim.fn.strdisplaywidth(self)
|
||||
-- end
|
||||
--
|
||||
-- -- 各种风格的基础宽度
|
||||
-- local style_width = {
|
||||
-- -- float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
|
||||
-- cursor = 60,
|
||||
-- }
|
||||
-- local s_to_b = true -- 从小到大排列
|
||||
--
|
||||
-- local m_fields -- 待格式化的字段
|
||||
-- local m_indent -- 每行的行首缩进
|
||||
-- local m_tot_width -- 所有字段加起来的长度(不包括缩进和间隔)
|
||||
-- local m_interval -- 每个字段的间隔
|
||||
-- local m_win_width -- 需要被格式化窗口的高度
|
||||
-- local m_item_width -- 每个字段的宽度
|
||||
-- local m_size
|
||||
--
|
||||
-- local function caculate_format()
|
||||
-- local width = m_win_width - m_item_width[1]
|
||||
-- local cols = 0
|
||||
-- for i = 2, #m_fields do
|
||||
-- width = width - m_item_width[i] - m_interval
|
||||
-- if width < 0 then
|
||||
-- cols = i - 1
|
||||
-- break
|
||||
-- else
|
||||
-- cols = i
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- return math.ceil(#m_fields / cols), cols
|
||||
-- end
|
||||
--
|
||||
-- local function format_to_line()
|
||||
-- local line = m_fields[1]
|
||||
-- if m_size == 1 then
|
||||
-- --- Center Align
|
||||
-- local space = math.floor((m_win_width - m_item_width[1]) / 2)
|
||||
-- line = (' '):rep(space) .. line
|
||||
-- else
|
||||
-- local space = math.floor((m_win_width - m_tot_width) / m_size - 1)
|
||||
-- for i = 2, m_size do
|
||||
-- line = line .. (' '):rep(space) .. m_fields[i]
|
||||
-- end
|
||||
-- end
|
||||
-- return line
|
||||
-- end
|
||||
--
|
||||
--
|
||||
-- local function sort_tables()
|
||||
-- table.sort(m_item_width, function (a, b)
|
||||
-- return a > b
|
||||
-- end)
|
||||
--
|
||||
-- table.sort(m_fields, function (a, b)
|
||||
-- return a:width() > b:width()
|
||||
-- end)
|
||||
-- end
|
||||
--
|
||||
--
|
||||
-- local function format_to_multilines()
|
||||
-- local lines = {}
|
||||
-- sort_tables()
|
||||
--
|
||||
-- --- NOTE : 计算应该格式化成多少行和列
|
||||
-- local rows, cols = caculate_format()
|
||||
-- local rest = #m_fields % cols
|
||||
-- if rest == 0 then
|
||||
-- rest = cols
|
||||
-- end
|
||||
--
|
||||
-- local s_width = m_item_width[1] -- 列中最宽的字符串宽度
|
||||
-- -- NOTE : 第一列不需要加空格
|
||||
-- for i = 1, rows do
|
||||
-- local idx = s_to_b and rows - i + 1 or i
|
||||
-- local space = (' '):rep(s_width - m_item_width[i])
|
||||
-- lines[idx] = m_fields[i] .. space -- NOTE 由大到小
|
||||
-- end
|
||||
--
|
||||
-- local index = rows + 1 -- 最宽字符的下标
|
||||
-- local interval = (' '):rep(m_interval) -- 每个字符串间的间隙
|
||||
--
|
||||
-- for j = 2, cols do -- 以列为单位遍历
|
||||
-- s_width = m_item_width[index]
|
||||
-- local stop = (j > rest and rows - 1 or rows)
|
||||
-- for i = 1, stop do
|
||||
-- local idx = s_to_b and stop - i + 1 or i -- 当前操作的行数
|
||||
-- local item = index + i - 1 -- 当前操作的字段数
|
||||
-- local space = (' '):rep(s_width - m_item_width[item]) -- 对齐空格
|
||||
--
|
||||
-- lines[idx] = lines[idx] .. interval .. m_fields[item] .. space -- NOTE 从大到小
|
||||
-- end
|
||||
-- index = index + stop -- 更新最宽字符的下标
|
||||
-- end
|
||||
--
|
||||
-- return lines
|
||||
-- end
|
||||
--
|
||||
--
|
||||
-- local function get_formatted_lines()
|
||||
-- local lines = {}
|
||||
-- -- NOTE : 判断能否格式化成一行
|
||||
-- local line_size = m_tot_width + (#m_fields * m_interval)
|
||||
-- if line_size > m_win_width then
|
||||
-- lines = format_to_multilines()
|
||||
-- else
|
||||
-- lines[1] = format_to_line()
|
||||
-- end
|
||||
--
|
||||
-- -- NOTE :进行缩进
|
||||
-- if m_indent > 0 then
|
||||
-- for i, v in ipairs(lines) do
|
||||
-- lines[i] = (' '):rep(m_indent) .. v
|
||||
-- end
|
||||
-- end
|
||||
-- return lines
|
||||
-- end
|
||||
--
|
||||
-- ---将组件格式化成相应的vim支持的lines格式
|
||||
-- ---@param style string 窗口的风格
|
||||
-- ---@param fields string[] 需要格式化的字段
|
||||
-- ---@param indent? number 缩进的长度
|
||||
-- ---@return string[] lines 便于vim.api.nvim_buf_set_lines
|
||||
-- M.to_lines = function(style, fields, indent)
|
||||
--
|
||||
-- local length = 0
|
||||
-- local width = 0
|
||||
-- local item_size = {}
|
||||
-- for i, v in ipairs(fields) do
|
||||
-- width = v:width()
|
||||
-- item_size[i] = width
|
||||
-- length = length + width
|
||||
-- end
|
||||
--
|
||||
-- m_indent = indent or 0
|
||||
-- m_win_width = style_width[style] - m_indent
|
||||
-- m_fields = fields
|
||||
-- m_tot_width = length
|
||||
-- m_item_width = item_size
|
||||
-- m_interval = m_win_width > 50 and 6 or 4
|
||||
-- m_size = #fields
|
||||
--
|
||||
-- return get_formatted_lines()
|
||||
-- end
|
||||
--
|
||||
-- local test = {
|
||||
-- 'isjlk测试dj',
|
||||
-- '测试一下..',
|
||||
-- }
|
||||
--
|
||||
-- local lines = M.to_lines('cursor', test)
|
||||
--
|
||||
-- -- print('===========================================')
|
||||
-- -- for _, v in ipairs(test) do
|
||||
-- -- print(v .. ' width:', v:width())
|
||||
-- -- end
|
||||
-- -- print('===========================================')
|
||||
-- -- print('===========================================')
|
||||
-- -- print('===========================================')
|
||||
--
|
||||
-- -- print('type is :' .. type(lines) .. ' size is :' .. #lines[1])
|
||||
--
|
||||
-- for _, v in ipairs(test) do
|
||||
-- print(v .. ' width:', v:width())
|
||||
-- print(v:width())
|
||||
-- end
|
||||
-- print('===========================================')
|
||||
-- print('===========================================')
|
||||
-- print('===========================================')
|
||||
|
||||
-- print('type is :' .. type(lines) .. ' size is :' .. #lines[1])
|
||||
|
||||
for _, v in ipairs(test) do
|
||||
print(v:width())
|
||||
end
|
||||
|
||||
-- lines = M.to_lines('cursor', {
|
||||
-- 'ajlkasj',
|
||||
-- 'jklasjldajjnn测试',
|
||||
-- '测试将安得拉蓝色',
|
||||
-- 'cool this',
|
||||
-- }, 4)
|
||||
|
||||
-- for _, v in ipairs(lines) do
|
||||
-- print(v)
|
||||
-- end
|
||||
return M
|
||||
|
||||
--
|
||||
-- -- lines = M.to_lines('cursor', {
|
||||
-- -- 'ajlkasj',
|
||||
-- -- 'jklasjldajjnn测试',
|
||||
-- -- '测试将安得拉蓝色',
|
||||
-- -- 'cool this',
|
||||
-- -- }, 4)
|
||||
--
|
||||
-- -- for _, v in ipairs(lines) do
|
||||
-- -- print(v)
|
||||
-- -- end
|
||||
-- return M
|
||||
--
|
||||
|
@ -1,18 +1,12 @@
|
||||
local a = {
|
||||
'test1',
|
||||
'test2',
|
||||
'test3'
|
||||
}
|
||||
-- 记录开始时间
|
||||
local starttime = os.clock(); --> os.clock()用法
|
||||
|
||||
|
||||
local function test(tmp)
|
||||
tmp = {
|
||||
'bbbbbb'
|
||||
}
|
||||
for i = 1, 10, 2 do
|
||||
print(i)
|
||||
end
|
||||
|
||||
|
||||
test(a)
|
||||
for i, v in ipairs(a) do
|
||||
print(v)
|
||||
end
|
||||
-- 记录结束时间
|
||||
local endtime = os.clock(); --> os.clock()用法
|
||||
print(string.format("end time : %.4f", endtime));
|
||||
print(string.format("cost time : %.4f", endtime - starttime));
|
||||
|
Loading…
x
Reference in New Issue
Block a user