Compare commits

..

36 Commits

Author SHA1 Message Date
tqcq
e2fe39eeff fix fetch word 2025-03-20 17:00:31 +08:00
tqcq
35c6c48b2e feat support db_url 2025-03-18 03:34:15 +00:00
Zoran
3ebcd7b785
Merge pull request #56 from TD-Sky/v2
fix(font): replace removed characters with valids
2024-04-21 14:58:21 +08:00
TD-Sky
dd1fe3caae fix(font): replace removed characters with valids 2024-04-21 14:52:58 +08:00
Zoran
98507facfe
Merge pull request #53 from MoetaYuko/v2
Windows fixes
2024-02-13 15:06:38 +08:00
Moeta Yuko
a13c09e95f feat: use powershell to unzip on windows 2024-02-13 14:50:55 +08:00
Moeta Yuko
863213bbc8 fix: fix plugin_dir and use left slash as path separator for windows
Fixes #46
2024-02-13 14:50:55 +08:00
Moeta Yuko
4b9e8a7ab9 chore: remove useless relative_path 2024-02-13 13:29:16 +08:00
Zoran
50c2f003f4
Merge pull request #38 from Xiao-M0/v2
feat: get visual-block text
2023-05-16 16:07:03 +08:00
xiaomo
2de2a713af refactor: add get_range() 2023-05-15 12:43:42 +08:00
xiaomo
cb47a09cbc feat: get visual-block text 2023-05-15 09:04:40 +08:00
JuanZoran
5504ab5757 chore: remove dependency of node and fix up termux tts name 2023-05-14 12:58:06 +08:00
JuanZoran
edc6b89086 chore: add MIT License 2023-05-14 10:55:10 +08:00
JuanZoran
586cd6ff08 fix: system checker mistake 2023-05-13 19:36:40 +08:00
Zoran
b5e626a88c
Merge pull request #34 from Xiao-M0/v2
feat: add win wsl, remove python and nodejs dependencies
2023-05-13 19:07:36 +08:00
xiaomo
e993dc12be fix: get_select get_lines 2023-05-13 18:16:28 +08:00
xiaomo
871cc1e48a refactor: wsl 2023-05-13 18:13:32 +08:00
小尛
6e02f3b1ba fix: update exchange_map 2023-05-12 20:39:46 +08:00
小尛
377c84c146 fix: double quote error 2023-05-12 20:27:39 +08:00
小尛
ba08913b1e feat: get_lines 2023-04-25 13:48:52 +08:00
JuanZoran
854bce7b5a chore: remove useless code 2023-04-24 20:58:56 +08:00
小尛
a48caf51e1 remove: node 2023-04-24 19:57:33 +08:00
小尛
24a838646d feat: add win wsl 2023-04-24 18:48:36 +08:00
Zoran
156e03306a
Merge pull request #33 from Xiao-M0/v2
fix: win separator
2023-04-24 13:04:43 +08:00
小尛
0a1b6cf742 feat: say.py 2023-04-24 13:02:48 +08:00
小尛
758b9c0b33 fix: win separator 2023-04-24 12:42:59 +08:00
JuanZoran
3faab735fb chore: make hover window focusable and update docs 2023-04-16 16:38:39 +08:00
JuanZoran
335c5079cc docs: update README 2023-04-08 21:46:29 +08:00
JuanZoran
38b8e20729 chore: close window and buffer more safely 2023-04-07 19:05:24 +08:00
JuanZoran
fcde85544a feat: use a non-invasive keymap define method 2023-04-06 13:38:19 +08:00
JuanZoran
2ae2effecc chore: more spinner style support 2023-04-04 16:19:06 +08:00
JuanZoran
da6e717f2c feat: use a non-invasive keymap define method 2023-04-02 18:02:21 +08:00
JuanZoran
576f1eb66a feat: add termux tts support 2023-04-02 13:34:54 +08:00
JuanZoran
9357574b5c chore: sync 2023-04-01 09:59:09 +08:00
JuanZoran
987e1a3341 test: add simple window unit test 2023-03-31 12:51:11 +08:00
JuanZoran
b27bc4ed26 fix: add util unit test and fix util.center mistake 2023-03-31 01:04:36 +08:00
26 changed files with 996 additions and 509 deletions

21
LICENCE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Zoran
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

225
README.md
View File

@ -2,51 +2,48 @@
<!--toc:start-->
- [Trans.nvim](#transnvim) - [注意: 当前分支目前没有发布, README.md 的描述并不准确, 遇到问题请切换到 `main`分支或者联系我](#注意-当前分支目前没有发布-readmemd-的描述并不准确-遇到问题请切换到-main分支或者联系我)
- [Trans.nvim](#transnvim)
- [特点](#特点)
- [屏幕截图](#屏幕截图)
- [演示](#演示)
- [离线查询](#离线查询)
- [\*在线查询\*\* (有道)](#在线查询-有道)
- [在线查询演示 (有道)](#在线查询演示-有道)
- [主题](#主题)
- [安装](#安装)
- [配置](#配置)
- [快捷键绑定](#快捷键绑定)
- [高亮组](#高亮组)
- [声明](#声明)
- [感谢](#感谢)
- [贡献](#贡献)
- [从 v1 (main)分支迁移](#从-v1-main分支迁移)
- [待办 (画大饼)](#待办-画大饼)
- [项目情况](#项目情况)
<!--toc:end-->
### 注意: 当前分支目前没有发布, README.md 的描述并不准确, 遇到问题请切换到 `main`分支或者联系我
> **插件默认词库的路径为插件目录**
例如: `lazy` 用户应该在 `$HOME/.local/share/nvim/lazy/Trans.nvim`
## 特点
- 使用纯 lua 编写, 速度极快
> `Lazy.nvim`的记录: <font color="#0099FF">`➜  Trans.nvim 0.82ms`</font>
- **可以定义快捷键读英文单词**
> 见 wiki
- `使用纯 lua 编写`
- 大部分功能可以自定义:
- 高亮
- 悬浮大小
- 排版顺序
- 弹窗大小
- `舒服窗口动画`
- etc (更多可以查看[配置](#配置))
- **完全离线** 的单词翻译体验 (可能后面会支持在线翻译)
- 🔍 高亮
- 👀 悬浮大小
- 📜 排版顺序
- 💬 弹窗大小
- 🎉 舒服窗口动画
- 更多可以查看[配置](#配置)
- `离线``在线`翻译的支持
- 支持显示:
- 柯林斯星级
- 牛津 3000 词汇
- 中文翻译
- 英文翻译 (不是英译中, 而是用英文解释)
- 词根
- 🌟 柯林斯星级
- 📚 牛津 3000 词汇
- 🇨🇳 中文翻译
- 🇺🇸 英文翻译 (不是英译中, 而是用英文解释)
- 🌱 词根
- etc
- 舒服的排版和`动画`
- 支持`平滑动画`
- 支持 `normal``visual`模式
> <font color='#FF9900'>不支持 visual-block mode</font>
- 本地词库单词量: `430w`
@ -61,13 +58,13 @@
https://user-images.githubusercontent.com/107862700/226175984-1a95bea7-8d66-450e-87e1-ba9c91c37ab8.mp4
### 在线查询 (有道)
### 在线查询演示 (有道)
https://user-images.githubusercontent.com/107862700/226176106-c2962dd3-d66c-499c-b44a-1f471b79fe38.mp4
**使用在线查询需要配置相应的 app_id 和 app_passwd**
在线查询配置见: [wiki](https://github.com/JuanZoran/Trans.nvim/wiki/%E9%85%8D%E7%BD%AE#%E5%9C%A8%E7%BA%BF%E6%9F%A5%E8%AF%A2%E9%85%8D%E7%BD%AE)
配置说明见: [wiki](https://github.com/JuanZoran/Trans.nvim/wiki/%E9%85%8D%E7%BD%AE#%E5%9C%A8%E7%BA%BF%E6%9F%A5%E8%AF%A2%E9%85%8D%E7%BD%AE)
### 主题
@ -96,7 +93,7 @@ _安装之前, 首先需要明确本插件的依赖:_
```lua
use {
'JuanZoran/Trans.nvim'
'JuanZoran/Trans.nvim',
run = function() require('Trans').install() end, -- 自动下载使用的本地词库
requires = 'kkharji/sqlite.lua', ,
-- 如果你不需要任何配置的话, 可以直接按照下面的方式启动
@ -139,12 +136,13 @@ use {
```lua
{
"JuanZoran/Trans.nvim",
build = function () require'Trans'.install() end,
keys = {
-- 可以换成其他你想映射的键
{ 'mm', mode = { 'n', 'x' }, '<Cmd>Translate<CR>', desc = ' Translate' },
{ 'mm', mode = { 'n', 'x' }, '<Cmd>Translate<CR>', desc = '󰊿 Translate' },
{ 'mk', mode = { 'n', 'x' }, '<Cmd>TransPlay<CR>', desc = ' Auto Play' },
-- 目前这个功能的视窗还没有做好可以在配置里将view.i改成hover
{ 'mi', '<Cmd>TranslateInput<CR>', desc = ' Translate From Input' },
{ 'mi', '<Cmd>TranslateInput<CR>', desc = '󰊿 Translate From Input' },
},
dependencies = { 'kkharji/sqlite.lua', },
opts = {
@ -157,40 +155,29 @@ use {
<font color="#FF9900">**注意事项**: </font>
- `install.sh`
- 使用了 `wget`下载词库, 安装请确保你的环境变量中存在 wget
- install.sh 下载后会自动将词库解压, 并移动到 `$HOME/.vim/dict`文件夹下
- 目前仅在 `Ubuntu22.04`的环境下测试通过
> 如果上述条件不符合, 请删掉 `run = 'install.sh'`部分, 考虑手动安装词库
> 如果上述条件满足, 仍出现问题, 欢迎在 issue 里向我反馈,我会及时尝试解决
- 下载词典的过程中, 需要能够 `流畅的访问github下载`
如果下载出现问题, 正常是会自动下载
> 词库文件压缩包大小为: **281M**
> 解压缩后的大小大概为: 1.2G
> 解压缩后的大小大概为: **1.2G**
- 安装后如果不能正常运行, 请尝试检查一下问题:
- 安装后如果不能正常运行, 清尝试运行 `checkhealth Trans`
- 本机是否已经安装了 `sqlite3`
> Linux 下安装:
> `sudo pacman -S sqlite # Arch`
> `sudo apt-get install sqlite3 libsqlite3-dev # Ubuntu`
- **`auto_play`** 的使用:
> **尝试运行 `checkhealth Trans`**
- `Linux` 需要安装`festival`
- **`auto_play`** 使用步骤:
> `sudo apt-get install festival festvox-kallpc16k`
> linux 只需要安装`festival`
> sudo apt-get install festival festvox-kallpc16k
> **_如果你想要设置音色发音可以访问:_** [Festival 官方](https://www.cstr.ed.ac.uk/projects/festival/morevoices.html)
> 可以选择英音、美音、男声、女声
**如果你想要设置音色,发音可以访问:** [Festival 官方](https://www.cstr.ed.ac.uk/projects/festival/morevoices.html)
可以选择英音、美音、男声、女声
> 其他操作系统
- `Termux` 需要安装`termux-api`
- 需要确保安装了`nodejs`
- 进入插件的`tts`目录运行`npm install`
> 如果`install`运行正常则自动安装,如果安装失败,请尝试手动安装
- `Mac` 使用系统的`say`命令
- `Windows` 使用原生的 Powershell 命令, 感谢[PR](https://github.com/JuanZoran/Trans.nvim/pull/34)
- `title`的配置,只对`neovim 0.9+`版本有效
@ -244,12 +231,16 @@ use {
## 配置
详细见**wiki**: [配置说明](https://github.com/JuanZoran/Trans.nvim/wiki/%E9%85%8D%E7%BD%AE)
详细见**wiki**: [基本配置说明](https://github.com/JuanZoran/Trans.nvim/wiki/%E9%85%8D%E7%BD%AE)
<details>
<summary>默认配置</summary>
```lua
require 'Trans'.setup {
default_conf = {
---@type string the directory for database file and password file
dir = require 'Trans'.plugin_dir,
debug = true,
---@type 'default' | 'dracula' | 'tokyonight' global Trans theme [see lua/Trans/style/theme.lua]
theme = 'default', -- default | tokyonight | dracula
strategy = {
@ -268,7 +259,7 @@ require 'Trans'.setup {
border = 'rounded',
title = vim.fn.has 'nvim-0.9' == 1 and {
{ '', 'TransTitleRound' },
{ ' Trans', 'TransTitle' },
{ '󰊿 Trans', 'TransTitle' },
{ '', 'TransTitleRound' },
} or nil, -- need nvim-0.9+
auto_play = true,
@ -294,11 +285,13 @@ require 'Trans'.setup {
split_width = 60,
padding = 10, -- padding for hover window width
keymaps = {
pageup = '[[',
pagedown = ']]',
pin = '<leader>[',
close = '<leader>]',
toggle_entry = '<leader>;',
-- INFO : No default keymaps anymore, please set it yourself
-- pageup = '<C-u>',
-- pagedown = '<C-d>',
-- pin = '<leader>[',
-- close = '<leader>]',
-- toggle_entry = '<leader>;',
-- play = '_', -- Deprecated
},
---@type string[] auto close events
@ -333,7 +326,7 @@ require 'Trans'.setup {
-- or use emoji
list = '●', -- ● | ○ | ◉ | ◯ | ◇ | ◆ | ▪ | ▫ | ⬤ | 🟢 | 🟡 | 🟣 | 🟤 | 🟠| 🟦 | 🟨 | 🟧 | 🟥 | 🟪 | 🟫 | 🟩 | 🟦
star = '', -- ⭐ | ✴ | ✳ | ✲ | ✱ | ✰ | ★ | ☆ | 🌟 | 🌠 | 🌙 | 🌛 | 🌜 | 🌟 | 🌠 | 🌌 | 🌙 |
notfound = ' ', --❔ | ❓ | ❗ | ❕|
notfound = '󰆆 ', --❔ | ❓ | ❗ | ❕|
yes = '✔', -- ✅ | ✔️ | ☑
no = '', -- ❌ | ❎ | ✖ | ✘ | ✗ |
cell = '■', -- ■ | □ | ▇ | ▏ ▎ ▍ ▌ ▋ ▊ ▉
@ -349,6 +342,8 @@ require 'Trans'.setup {
}
```
</details>
## 快捷键绑定
**示例:**
@ -361,66 +356,90 @@ vim.keymap.set({'n', 'x'}, 'mm', '<Cmd>Translate<CR>')
vim.keymap.set({'n', 'x'}, 'mk', '<Cmd>TransPlay<CR>') -- 自动发音选中或者光标下的单词
```
## 高亮组
> 默认定义
**窗口快捷键**
```lua
{
TransWord = {
require 'Trans'.setup {
frontend = {
hover = {
keymaps = {
-- pageup = 'whatever you want',
-- pagedown = 'whatever you want',
-- pin = 'whatever you want',
-- close = 'whatever you want',
-- toggle_entry = 'whatever you want',
},
},
},
}
}
```
> 当窗口没有打开的时候, key 会被使用`vim.api.nvim_feedkey`来执行
## 高亮组
所有主题可见 `lua/Trans/style/theme.lua`
<details>
<summary>默认主题</summary>
```lua
TransWord = {
fg = '#7ee787',
bold = true,
},
TransPhonetic = {
}
TransPhonetic = {
link = 'Linenr'
},
TransTitle = {
}
TransTitle = {
fg = '#0f0f15',
bg = '#75beff',
bold = true,
},
TransTitleRound = {
}
TransTitleRound = {
fg = '#75beff',
},
TransTag = {
}
TransTag = {
-- fg = '#e5c07b',
link = '@tag'
},
TransExchange = {
}
TransExchange = {
link = 'TransTag',
},
TransPos = {
}
TransPos = {
link = 'TransTag',
},
TransTranslation = {
}
TransTranslation = {
link = 'TransWord',
},
TransDefinition = {
}
TransDefinition = {
link = 'Moremsg',
},
TransWin = {
}
TransWin = {
link = 'Normal',
},
TransBorder = {
}
TransBorder = {
fg = '#89B4FA',
},
TransCollins = {
}
TransCollins = {
fg = '#faf743',
bold = true,
},
TransFailed = {
}
TransFailed = {
fg = '#7aa89f',
},
TransWaitting = {
}
TransWaitting = {
link = 'MoreMsg'
},
TransWeb = {
-- TODO :
}
TransWeb = {
link = 'MoreMsg',
}
}
}
```
</details>
## 声明
- 本插件词典基于[ECDICT](https://github.com/skywind3000/ECDICT)
@ -433,20 +452,24 @@ vim.keymap.set({'n', 'x'}, 'mk', '<Cmd>TransPlay<CR>') -- 自动发音选中或
## 贡献
> 更新比较频繁, 文档先鸽了
> 更新比较频繁, 文档先鸽了 (wiki 写了一小部分
> 如果你想要参加这个项目, 可以提 issue, 我会把文档补齐
## 从 v1 (main)分支迁移
见[wiki](<https://github.com/JuanZoran/Trans.nvim/wiki/%E4%BB%8E(v1)main%E5%88%86%E6%94%AF%E8%BF%81%E7%A7%BB>)
## 待办 (画大饼)
- [x] 快捷键定义
- [x] 自动读音
- [x] 在线多引擎异步查询
- [x] `句子翻译` | `中翻英` 的支持
- [ ] 迁移文档
- [x] 迁移文档
- [ ] 多风格样式查询
- [ ] 重新录制屏幕截图示例
- [ ] 变量命名的支持
- [ ] 历史查询结果保存
- [ ] 翻译结果替换
## 项目情况

View File

@ -129,7 +129,7 @@ Packer.nvim ~
requires = { 'kkharji/sqlite.lua', },
config = function()
require("Trans").setup {} -- 启动Trans
vim.keymap.set({"n", 'x'}, "mm", '<Cmd>Translate<CR>', { desc = ' Translate' }) -- 自动判断virtual 还是 normal 模式
vim.keymap.set({"n", 'x'}, "mm", '<Cmd>Translate<CR>', { desc = '󰊿 Translate' }) -- 自动判断virtual 还是 normal 模式
vim.keymap.set({'n', 'x'}, 'mk', '<Cmd>TransPlay<CR>', {desc = ' 自动发音'}) -- 自动发音选中或者光标下的单词
end
}
@ -142,11 +142,11 @@ Lazy.nvim ~
"JuanZoran/Trans.nvim",
keys = {
-- 可以换成其他你想映射的键
{ 'mm', mode = { 'n', 'x' }, '<Cmd>Translate<CR>', desc = ' Translate' },
{ 'mm', mode = { 'n', 'x' }, '<Cmd>Translate<CR>', desc = '󰊿 Translate' },
{ 'mk', mode = { 'n', 'x' }, '<Cmd>TransPlay<CR>', desc = ' 自动发音' },
-- 目前这个功能的视窗还没有做好可以在配置里将view.i改成hover
{ 'mi', '<Cmd>TranslateInput<CR>', desc = ' Translate From Input' },
{ 'mi', '<Cmd>TranslateInput<CR>', desc = '󰊿 Translate From Input' },
},
dependencies = { 'kkharji/sqlite.lua', },
opts = {
@ -301,7 +301,7 @@ Festival配置(仅针对linux用户) ~
-- or use emoji
list = '●', -- ● | ○ | ◉ | ◯ | ◇ | ◆ | ▪ | ▫ | ⬤ | 🟢 | 🟡 | 🟣 | 🟤 | 🟦 | 🟨 | 🟧 | 🟥 | 🟪 | 🟫 | 🟩 | 🟠 | 🟦 | 🟨 | 🟧 | 🟥 | 🟪 | 🟫 | 🟩 | 🟠
star = '', -- ⭐ | ✴ | ✳ | ✲ | ✱ | ✰ | ★ | ☆ | 🌟 | 🌠 | 🌙 | 🌛 | 🌜 | 🌟 | 🌠 | 🌌 | 🌙 |
notfound = ' ', --❔ | ❓ | ❗ | ❕|
notfound = '󰆆 ', --❔ | ❓ | ❗ | ❕|
yes = '✔', -- ✅ | ✔️ | ☑
no = '', -- ❌ | ❎ | ✖ | ✘ | ✗ |
cell = '■', -- ■ | □ | ▇ | ▏ ▎ ▍ ▌ ▋ ▊ ▉ █

View File

@ -15,4 +15,9 @@
- [ ] Unlimit width for sentence
已知问题:
1. 缓存了的单词, 无法使用toggle_entry 进入页面
2. 加载配置需要输入所有表的key
- default_strategy can't deal with table correctly

View File

@ -1,7 +1,7 @@
local Trans = require 'Trans'
local db = require 'sqlite.db'
local path = Trans.conf.dir .. Trans.separator .. 'ultimate.db'
local path = Trans.conf.dir .. '/ultimate.db'
local dict = db:open(path)
local db_name = 'stardict'
vim.api.nvim_create_autocmd('VimLeavePre', {
@ -99,6 +99,8 @@ local formatter = {
['p'] = '过去式 ',
['r'] = '比较级 ',
['t'] = '最高级 ',
['b'] = '比较级 ',
['z'] = '最高级 ',
['s'] = '复数 ',
['d'] = '过去分词 ',
['i'] = '现在分词 ',

View File

@ -2,7 +2,7 @@ local api, fn = vim.api, vim.fn
---@class TransBuffer
---@field bufnr integer buffer handle
---@field [number] string|TransNode|TransNode[] buffer[line] content
---@field [integer] string|TransNode|TransNode[] buffer[line] content
local buffer = {}
-- INFO : corountine can't invoke C function
@ -37,7 +37,7 @@ end
---Destory buffer
function buffer:destroy()
api.nvim_buf_delete(self.bufnr, { force = true })
pcall(api.nvim_buf_delete, self.bufnr, { force = true })
end
---Set buffer load keymap
@ -91,11 +91,7 @@ end
---@return integer
function buffer:line_count()
local line_count = api.nvim_buf_line_count(self.bufnr)
if line_count == 1 and self[1] == '' then
return 0
end
return line_count
return line_count == 1 and self[1] == '' and 0 or line_count
end
---Set line content
@ -151,11 +147,11 @@ buffer.__index = function(self, key)
end
end
buffer.__newindex = function(self, key, nodes)
buffer.__newindex = function(self, key, values)
if type(key) == 'number' then
self:setline(nodes, key)
self:setline(values, key)
else
rawset(self, key, nodes)
rawset(self, key, values)
end
end

View File

@ -6,7 +6,7 @@
return {
---@type string the directory for database file and password file
dir = require 'Trans'.plugin_dir,
warning = true,
db_url = 'https://github.com/skywind3000/ECDICT-ultimate/releases/download/1.0.0/ecdict-ultimate-sqlite.zip',
debug = true,
---@type 'default' | 'dracula' | 'tokyonight' global Trans theme [see lua/Trans/style/theme.lua]
theme = 'default', -- default | tokyonight | dracula
@ -26,7 +26,7 @@ return {
border = 'rounded',
title = vim.fn.has 'nvim-0.9' == 1 and {
{ '', 'TransTitleRound' },
{ ' Trans', 'TransTitle' },
{ '󰊿 Trans', 'TransTitle' },
{ '', 'TransTitleRound' },
} or nil, -- need nvim-0.9+
auto_play = true,
@ -52,11 +52,12 @@ return {
split_width = 60,
padding = 10, -- padding for hover window width
keymaps = {
pageup = '[[',
pagedown = ']]',
pin = '<leader>[',
close = '<leader>]',
toggle_entry = '<leader>;',
-- pageup = '<C-u>',
-- pagedown = '<C-d>',
-- pin = '<leader>[',
-- close = '<leader>]',
-- toggle_entry = '<leader>;',
-- play = '_', -- Deprecated
},
---@type string[] auto close events
@ -91,7 +92,7 @@ return {
-- or use emoji
list = '', -- ● | ○ | ◉ | ◯ | ◇ | ◆ | ▪ | ▫ | ⬤ | 🟢 | 🟡 | 🟣 | 🟤 | 🟠| 🟦 | 🟨 | 🟧 | 🟥 | 🟪 | 🟫 | 🟩 | 🟦
star = '', -- ⭐ | ✴ | ✳ | ✲ | ✱ | ✰ | ★ | ☆ | 🌟 | 🌠 | 🌙 | 🌛 | 🌜 | 🌟 | 🌠 | 🌌 | 🌙 |
notfound = ' ', --❔ | ❓ | ❗ | ❕|
notfound = '󰆆 ', --❔ | ❓ | ❗ | ❕|
yes = '', -- ✅ | ✔️ | ☑
no = '', -- ❌ | ❎ | ✖ | ✘ | ✗ |
cell = '', -- ■ | □ | ▇ | ▏ ▎ ▍ ▌ ▋ ▊ ▉

View File

@ -37,7 +37,7 @@ function M.new(opts)
data.backends[i] = Trans.backend[name]
end
if Trans.util.is_English(str) then
if Trans.util.is_english(str) then
data.from = 'en'
data.to = 'zh'
else

View File

@ -5,7 +5,7 @@ return function()
local fn = vim.fn
-- INFO :Check ultimate.db exists
local dir = Trans.conf.dir
local path = dir .. 'ultimate.db'
local path = dir .. '/ultimate.db'
if fn.isdirectory(dir) == 0 then
fn.mkdir(dir, 'p')
@ -17,17 +17,16 @@ return function()
end
-- INFO :Download ultimate.db
local uri = 'https://github.com/skywind3000/ECDICT-ultimate/releases/download/1.0.0/ecdict-ultimate-sqlite.zip'
local zip = dir .. 'ultimate.zip'
local uri = Trans.conf.db_url
local zip = dir .. '/ultimate.zip'
local continue = fn.filereadable(zip) == 1
local handle = function(output)
if output.exit == 0 and fn.filereadable(zip) then
if fn.executable 'unzip' == 0 then
vim.notify('unzip not found, Please unzip ' .. zip .. 'manually', vim.log.ERROR)
return
end
local cmd = string.format('unzip %s -d %s', zip, dir)
local cmd =
Trans.system == 'win' and
string.format('powershell.exe -Command "Expand-Archive -Force %s %s"', zip, dir) or
fn.executable('unzip') == 1 and string.format('unzip %s -d %s', zip, dir) or
error('unzip not found, Please unzip ' .. zip .. ' manually')
local status = os.execute(cmd)
os.remove(zip)
if status == 0 then
@ -40,7 +39,6 @@ return function()
vim.notify(debug_message, vim.log.ERROR)
end
Trans.curl.get(uri, {
output = zip,
callback = handle,
@ -49,9 +47,4 @@ return function()
local message = continue and 'Continue download database' or 'Begin to download database'
vim.notify(message, vim.log.levels.INFO)
-- INFO : Install tts dependencies
if fn.has 'linux' == 0 and fn.has 'mac' == 0 then
os.execute 'cd ./tts && npm install'
end
end

View File

@ -52,12 +52,4 @@ return function(opts)
set_strategy_opts(conf)
define_highlights(conf)
if Trans.conf.warning then
vim.notify([[
v2已经发布, :
https://github.com/JuanZoran/Trans.nvim
使(v2)
]], vim.log.levels.WARN)
end
end

View File

@ -59,8 +59,7 @@ local strategy = {
local name = backend.name
---@cast backend TransBackend
while result[name] == nil do
if not update(backend) then break end
while result[name] == nil and update(backend) do
end
if result[name] then return true end
@ -72,12 +71,13 @@ local strategy = {
}
-- HACK : Core process logic
local function process(opts)
opts = init_opts(opts)
local str = opts.str
if not str or str == '' then return end
if not opts.str or opts.str == '' then return end
local str = opts.str:match("(%w+)")
-- Find in cache

View File

@ -3,20 +3,23 @@ local fn, api = vim.fn, vim.api
---@class TransUtil
local M = require 'Trans'.metatable 'util'
---Get the range of visual modes
---@return table
function M.get_range()
local _start = fn.getpos 'v'
local _end = fn.getpos '.'
local s_row, e_row = math.min(_start[2], _end[2]), math.max(_start[2], _end[2])
local s_col, e_col = math.min(_start[3], _end[3]), math.max(_start[3], _end[3])
return { s_row, e_row, s_col, e_col }
end
---Get selected text
---@return string
function M.get_select()
local _start = fn.getpos 'v'
local _end = fn.getpos '.'
local s_row, e_row, s_col, e_col = unpack(M.get_range())
if _start[2] > _end[2] or (_start[3] > _end[3] and _start[2] == _end[2]) then
_start, _end = _end, _start
end
local s_row, s_col = _start[2], _start[3]
local e_row, e_col = _end[2], _end[3]
-- print(s_row, e_row, s_col, e_col)
---@type string
---@diagnostic disable-next-line: assign-type-mismatch
local line = fn.getline(e_row)
@ -24,7 +27,6 @@ function M.get_select()
---@diagnostic disable-next-line: param-type-mismatch
e_col = vim.str_byteindex(line, uidx)
if s_row == e_row then
return line:sub(s_col, e_col)
else
@ -32,7 +34,43 @@ function M.get_select()
local e = #lines
lines[1] = lines[1]:sub(s_col)
lines[e] = line:sub(1, e_col)
return table.concat(lines)
return table.concat(lines, ' ')
end
end
---Get selected text
---@return string
function M.get_lines()
local s_row, e_row = unpack(M.get_range())
if s_row == e_row then
return fn.getline(s_row)
else
local lines = fn.getline(s_row, e_row)
return table.concat(lines, " ")
end
end
---Get selected text
---@return string
function M.get_block()
local s_row, e_row, s_col, e_col = unpack(M.get_range())
---@type string
---@diagnostic disable-next-line: assign-type-mismatch
local line = fn.getline(e_row)
local uidx = vim.str_utfindex(line, math.min(#line, e_col))
---@diagnostic disable-next-line: param-type-mismatch
e_col = vim.str_byteindex(line, uidx)
if s_row == e_row then
return line:sub(s_col, e_col)
else
local lines = fn.getline(s_row, e_row)
for col, l in pairs(lines) do
lines[col] = l:sub(s_col,e_col)
end
return table.concat(lines, " ")
end
end
@ -52,7 +90,12 @@ function M.get_str(mode)
return fn.input '需要翻译的字符串: '
end,
V = function()
print 'TODO'
api.nvim_input '<Esc>'
return M.get_lines()
end,
[''] = function()
api.nvim_input '<Esc>'
return M.get_block()
end,
})[mode]():match '^%s*(.-)%s*$'
end
@ -60,6 +103,7 @@ end
---Puase coroutine for {ms} milliseconds
---@param ms integer
function M.pause(ms)
assert(ms)
local co = coroutine.running()
vim.defer_fn(function()
coroutine.resume(co)
@ -70,7 +114,7 @@ end
---Detect whether the string is English
---@param str string
---@return boolean
function M.is_English(str)
function M.is_english(str)
local char = { str:byte(1, -1) }
for i = 1, #str do
if char[i] > 128 then
@ -114,7 +158,6 @@ function M.center(node, win_width)
end
local str = node[1]
win_width = str:width()
local space = math.max(0, math.floor((win_width - str:width()) / 2))
node[1] = string.rep(' ', space) .. str
return node
@ -174,7 +217,7 @@ end
---@param str string
---@return boolean
function M.is_word(str)
return str:match '%w+' == str
return str:find '%W' == nil
end
---@param list any[]

View File

@ -124,7 +124,8 @@ function window:try_close()
}
end
api.nvim_win_close(self.winid, true)
pcall(api.nvim_win_close, self.winid, true)
end
---Set window local highlight group
@ -161,21 +162,7 @@ window.__index = window
---@alias WindowOpts
---|{style: string, border: string, focusable: boolean, noautocmd?: boolean, relative: string, width: integer, height: integer, col: integer, row: integer, zindex?: integer, title?: table | string}
---@class TransWindowOpts
local default_opts = {
enter = false,
winid = -1,
---@type WindowOpts
win_opts = {
style = 'minimal',
border = 'rounded',
focusable = false,
noautocmd = true,
},
}
---|{style: string, border: string, focusable: boolean, noautocmd?: boolean, relative: 'mouse'|'cursor'|'editor'|'win', width: integer, height: integer, col: integer, row: integer, zindex?: integer, title?: table | string}
---@class TransWindow
@ -197,11 +184,37 @@ local default_opts = {
-- relative = relative,
-- }
local default_opts = {
enter = false,
winid = -1,
---@type WindowOpts
win_opts = {
-- INFO : ensured options
-- col
-- row
-- width
-- height
-- relative
-- zindex
style = 'minimal',
border = 'rounded',
focusable = true,
noautocmd = true,
},
}
---@class TransWindowOpts
---@field buffer TransBuffer attached buffer object
---@field enter? boolean cursor should [enter] window when open,default: false
---@field win_opts WindowOpts window config [**When open**]
---@field animation? table? Hover Window Animation
---Create new window
---@param opts TransWindowOpts window config
---@return TransWindow
function window.new(opts)
opts = vim.tbl_deep_extend('keep', opts, default_opts)
opts.animation = opts.animation or { interval = 12 }
local win = setmetatable(opts, window)
---@cast win TransWindow

View File

@ -1,5 +1,6 @@
---@type Trans
local Trans = require 'Trans'
local util = Trans.util
-- FIXME :Adjust Window Size
@ -18,16 +19,16 @@ local M = Trans.metatable('frontend.hover', {
M.__index = M
---Set up function which will be invoked when this module is loaded
function M.setup()
local set = vim.keymap.set
for action, key in pairs(M.opts.keymaps) do
set('n', key, function()
local instance = M.get_active_instance()
if instance then
coroutine.wrap(instance.execute)(instance, action)
else
return key
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), 'n', false)
end
end)
end
@ -92,13 +93,13 @@ function M:init_window(opts)
buffer = self.buffer,
animation = m_opts.animation,
win_opts = {
relative = opts.relative or 'cursor',
col = opts.col or 1,
row = opts.row or 1,
width = opts.width or m_opts.width,
height = opts.height or m_opts.height,
relative = opts.relative or 'cursor',
title = m_opts.title,
title_pos = m_opts.title and 'center' or nil,
title_pos = m_opts.title and 'center',
zindex = 100,
},
}
@ -118,7 +119,6 @@ end
---Get Check function for waiting
---@return fun(backend: TransBackend): boolean
function M:wait()
local util = Trans.util
local opts = self.opts
local buffer = self.buffer
local pause = util.pause
@ -126,7 +126,7 @@ function M:wait()
local spinner = Trans.style.spinner[opts.spinner]
local times = opts.width - spinner[1]:width()
local size = #spinner
local interval = math.floor(opts.timeout / opts.width)
local interval = math.floor(opts.timeout / times)
self:init_window {
height = 2,
@ -154,7 +154,7 @@ function M:fallback()
local buffer = self.buffer
buffer:wipe()
buffer[1] = Trans.util.center(fallback_msg, opts.width)
buffer[1] = util.center(fallback_msg, opts.width)
buffer:add_highlight(1, 'TransFailed')
if not self.window then
self:init_window {
@ -168,7 +168,7 @@ end
---Defer function when process done
function M:defer()
Trans.util.main_loop(function()
util.main_loop(function()
self.window:set('wrap', true)
self.buffer:set('modifiable', false)
@ -204,7 +204,6 @@ function M:process(data)
return
end
local util = Trans.util
local opts = self.opts
local buffer = self.buffer

View File

@ -36,15 +36,16 @@ local function check_binary_dependencies()
local binary_dependencies = {
'curl',
'sqlite3',
'unzip',
}
if has 'linux' == 1 then
binary_dependencies[3] = 'festival'
elseif has 'mac' == 1 then
binary_dependencies[3] = 'say'
else
binary_dependencies[3] = 'node'
end
binary_dependencies[3] = ({
win = nil,
mac = 'say',
linux = 'festival',
termux = 'termux-tts-speak',
})[Trans.system]
for _, dep in ipairs(binary_dependencies) do
if executable(dep) == 1 then
@ -56,7 +57,7 @@ local function check_binary_dependencies()
end
local function check_database()
local db_path = Trans.conf.dir .. Trans.separator .. 'ultimate.db'
local db_path = Trans.conf.dir .. '/ultimate.db'
if fn.filereadable(db_path) == 1 then
ok [[ultimate database found ]]
else
@ -68,7 +69,7 @@ local function check_database()
end
local function check_configure_file()
local path = fn.expand(Trans.conf.dir .. Trans.separator .. 'Trans.json')
local path = fn.expand(Trans.conf.dir .. '/Trans.json')
if not fn.filereadable(path) then
warn 'Backend configuration file[%s] not found'
end

View File

@ -18,28 +18,25 @@ end
---@field width function @Get string display width
---@field play function @Use tts to play string
local uname = vim.loop.os_uname().sysname
local system =
uname == 'Darwin' and 'mac' or
uname == 'Windows_NT' and 'win' or
uname == 'Linux' and (vim.fn.executable 'termux-api-start' == 1 and 'termux' or 'linux') or
error 'Unknown System, Please Report Issue'
local sep = vim.loop.os_uname().sysname == 'Windows' and '\\' or '/'
---@class Trans
---@field style table @Style module
---@field cache table<string, TransData> @Cache for translated data object
---@field plugin_dir string @Plugin directory
---@field separator string @Path separator
---@field system 'mac'|'win'|'termux'|'linux' @Operating system
local M = metatable('core', {
cache = {},
style = metatable 'style',
plugin_dir = debug.getinfo(1, 'S').source:sub(2):match('(.-)lua' .. sep .. 'Trans'),
separator = sep,
system = system,
plugin_dir = vim.fn.fnamemodify(debug.getinfo(1, 'S').source:sub(2), ':p:h:h:h'),
})
M.metatable = metatable
---Get abs_path of file
---@param path string[]
---@param is_dir boolean?
---@return string
function M.relative_path(path, is_dir)
return M.plugin_dir .. table.concat(path, sep) .. (is_dir and sep or '')
end
return M

View File

@ -29,248 +29,469 @@
-- SOFTWARE.
return {
dots = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
},
dots_negative = { -- dots2
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
},
dots_snake = { -- dots3
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
},
dots_footsteps = { -- dots10
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
},
dots_hop = { -- dots11
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
},
line = {
"-",
"\\",
"|",
"/",
'-',
'\\',
'|',
'/',
},
pipe = {
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
},
dots_ellipsis = { -- simpleDots
". ",
".. ",
"...",
" ",
'. ',
'.. ',
'...',
' ',
},
dots_scrolling = { -- simpleDotsScrolling
". ",
".. ",
"...",
" ..",
" .",
" ",
'. ',
'.. ',
'...',
' ..',
' .',
' ',
},
star = {
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
},
flip = {
"_",
"_",
"_",
"-",
"`",
"`",
'_',
'_',
'_',
'-',
'`',
'`',
"'",
"´",
"-",
"_",
"_",
"_",
'´',
'-',
'_',
'_',
'_',
},
hamburger = {
"",
"",
"",
'',
'',
'',
},
grow_vertical = { -- growVertical
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
},
grow_horizontal = { -- growHorizontal
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
},
noise = {
"",
"",
"",
'',
'',
'',
},
dots_bounce = { -- bounce
"",
"",
"",
"",
'',
'',
'',
'',
},
triangle = {
"",
"",
"",
"",
'',
'',
'',
'',
},
arc = {
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
},
circle = {
"",
"",
"",
'',
'',
'',
},
square_corners = { -- squareCorners
"",
"",
"",
"",
'',
'',
'',
'',
},
circle_quarters = { -- circleQuarters
"",
"",
"",
"",
'',
'',
'',
'',
},
circle_halves = { -- circleHalves
"",
"",
"",
"",
'',
'',
'',
'',
},
dots_toggle = { -- toggle
"",
"",
'',
'',
},
box_toggle = { -- toggle2
"",
"",
'',
'',
},
arrow = {
"",
"",
"",
"",
"",
"",
"",
"",
'',
'',
'',
'',
'',
'',
'',
'',
},
clock = {
"🕛 ",
"🕐 ",
"🕑 ",
"🕒 ",
"🕓 ",
"🕔 ",
"🕕 ",
"🕖 ",
"🕗 ",
"🕘 ",
"🕙 ",
"🕚 ",
'🕛 ',
'🕐 ',
'🕑 ',
'🕒 ',
'🕓 ',
'🕔 ',
'🕕 ',
'🕖 ',
'🕗 ',
'🕘 ',
'🕙 ',
'🕚 ',
},
earth = {
"🌍 ",
"🌎 ",
"🌏 ",
'🌍 ',
'🌎 ',
'🌏 ',
},
moon = {
"🌑 ",
"🌒 ",
"🌓 ",
"🌔 ",
"🌕 ",
"🌖 ",
"🌗 ",
"🌘 ",
'🌑 ',
'🌒 ',
'🌓 ',
'🌔 ',
'🌕 ',
'🌖 ',
'🌗 ',
'🌘 ',
},
dots_pulse = { -- point
"∙∙∙",
"●∙∙",
"∙●∙",
"∙∙●",
"∙∙∙",
'∙∙∙',
'●∙∙',
'∙●∙',
'∙∙●',
'∙∙∙',
},
fistBump = {
'🤜    🤛 ',
'🤜    🤛 ',
'🤜    🤛 ',
' 🤜  🤛  ',
'  🤜🤛   ',
' 🤜✨🤛   ',
'🤜 ✨ 🤛  ',
},
monkey = {
'🙈 ',
'🙈 ',
'🙉 ',
'🙊 '
},
soccerHeader = {
' 🧑⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
'🧑 ⚽️ 🧑 ',
},
weather = {
'☀️ ',
'☀️ ',
'☀️ ',
'🌤 ',
'⛅️ ',
'🌥 ',
'☁️ ',
'🌧 ',
'🌨 ',
'🌧 ',
'🌨 ',
'🌧 ',
'🌨 ',
'',
'🌨 ',
'🌧 ',
'🌨 ',
'☁️ ',
'🌥 ',
'⛅️ ',
'🌤 ',
'☀️ ',
'☀️ ',
},
speaker = {
'🔈 ',
'🔉 ',
'🔊 ',
'🔉 ',
},
smiley = {
'😄 ',
'😝 ',
},
toggle = {
'',
''
},
toggle10 = {
'',
'',
''
},
toggle11 = {
'',
''
},
toggle12 = {
'',
''
},
toggle13 = {
'=',
'*',
'-'
},
toggle2 = {
'',
''
},
toggle3 = {
'',
''
},
toggle4 = {
'',
'',
'',
''
},
toggle5 = {
'',
''
},
toggle6 = {
'',
''
},
toggle7 = {
'',
'⦿'
},
toggle8 = {
'',
''
},
toggle9 = {
'',
''
},
star = {
'',
'',
'',
'',
'',
''
},
star2 = {
'+',
'x',
'*'
},
orangeBluePulse = {
'🔸 ',
'🔶 ',
'🟠 ',
'🟠 ',
'🔶 ',
'🔹 ',
'🔷 ',
'🔵 ',
'🔵 ',
'🔷 ',
},
orangePulse = {
'🔸 ',
'🔶 ',
'🟠 ',
'🟠 ',
'🔶 '
},
mindblown = {
'😐 ',
'😐 ',
'😮 ',
'😮 ',
'😦 ',
'😦 ',
'😧 ',
'😧 ',
'🤯 ',
'💥 ',
'',
'  ',
'  ',
'  ',
},
hearts = {
'💛 ',
'💙 ',
'💜 ',
'💚 ',
'❤️ '
},
fingerDance = {
'🤘 ',
'🤟 ',
'🖖 ',
'',
'🤚 ',
'👆 '
},
christmas = {
'🌲',
'🎄'
},
circleHalves = {
'',
'',
'',
''
},
bouncingBall = {
'( ● )',
'( ● )',
'( ● )',
'( ● )',
'( ●)',
'( ● )',
'( ● )',
'( ● )',
'( ● )',
'(● )',
},
bluePulse = {
'🔹 ',
'🔷 ',
'🔵 ',
'🔵 ',
'🔷 '
},
betaWave = {
'ρββββββ',
'βρβββββ',
'ββρββββ',
'βββρβββ',
'ββββρββ',
'βββββρβ',
'ββββββρ',
},
}

View File

@ -4,9 +4,9 @@ local util = require 'Trans'.util
---@field [1] string text to be rendered
---@field render fun(self: TransNode, buffer: TransBuffer, line: number, col: number) render the node
---@class TransItem : TransNode
local item_meta = {
local item = (function()
---@class TransItem : TransNode
local mt = {
---@param self TransItem
---@param buffer TransBuffer
---@param line integer
@ -16,12 +16,23 @@ local item_meta = {
buffer:add_highlight(line, self[2], col, col + #self[1])
end
end,
}
}
mt.__index = mt
---@class TransText : TransNode
---@field step string
---@field nodes TransNode[]
local text_meta = {
---Basic item node
---@param tuple {[1]: string, [2]: string?}
---@return TransItem
return function(tuple)
return setmetatable(tuple, mt)
end
end)()
local text = (function()
---@class TransText : TransNode
---@field step string
---@field nodes TransNode[]
local mt = {
---@param self TransText
---@param buffer TransBuffer
---@param line integer
@ -36,30 +47,20 @@ local text_meta = {
col = col + #node[1] + len
end
end,
}
}
item_meta.__index = item_meta
text_meta.__index = text_meta
mt.__index = mt
---Basic item node
---@param tuple {[1]: string, [2]: string?}
---@return TransItem
local function item(tuple)
return setmetatable(tuple, item_meta)
end
---@param nodes {[number]: TransNode, step: string?}
---@return TransText
local function text(nodes)
---@param nodes {[number]: TransNode, step: string?}
---@return TransText
return function(nodes)
return setmetatable({
[1] = table.concat(util.list_fields(nodes, 1), nodes.step),
step = nodes.step,
nodes = nodes,
}, text_meta)
end
}, mt)
end
end)()
---@param args {[number]: TransNode, width: integer, spin: string?}
@ -85,7 +86,6 @@ end
---@class TransUtil
---@field node TransNodes
---@class TransNodes
return {
item = item,

View File

@ -6,6 +6,7 @@ _G.api = vim.api
_G.fn = vim.fn
_G.mock = require 'luassert.mock'
_G.stub = require 'luassert.stub'
string.width = api.nvim_strwidth
---@param func fun(buffer: TransBuffer)
---@return fun()

View File

@ -1,9 +1,92 @@
---@diagnostic disable: param-type-mismatch
require 'test.setup'
local util = Trans.util
describe('util.display_height', with_buffer(function(buffer)
--- TODO :
describe('util.display_height', function()
it('can calculate the height of lines when window with wrap option', function()
local lines = {
'1234567890',
'1234567890',
'1234567890',
'1234567890',
'1234567890',
'1234567890',
'1234567890',
'1234567890',
'1234567890',
}
assert.are.equal(#lines, util.display_height(lines, 10))
assert.are.equal(#lines, util.display_height(lines, 11))
assert.are.equal(2 * #lines, util.display_height(lines, 9))
-- Unicode width test
local u_lines = {
'12345678👍', -- 10
'あうえお', -- 8
'𠮷野い𠮷家野家家', -- 16
'👍👍👍お家', -- 10
}
assert.are.equal(4, util.display_height(u_lines, 20))
assert.are.equal(4, util.display_height(u_lines, 16))
assert.are.equal(5, util.display_height(u_lines, 10))
assert.are.equal(7, util.display_height(u_lines, 8))
assert.are.equal(9, util.display_height(u_lines, 7))
end)
end))
end)
describe('util.display_width', function()
it('can calculate the max width of lines', function()
local lines = {
'1234567890',
'123456789',
'12345678',
'1234567',
'123456',
'12345',
'1234',
'123',
'12',
'1',
}
assert.are.equal(10, util.display_width(lines))
-- Unicode width test
local u_lines = {
'12345678👍', -- 10
'あうえお', -- 8
'𠮷野い𠮷家野家家', -- 16
'👍👍👍お家', -- 10
}
assert.are.equal(16, util.display_width(u_lines))
end)
end)
describe('util.center', function()
it('will return the node if its width more than width', function()
local node = i { '1234567890' }
assert.are.same(node, util.center(node, 9))
end)
it('will auto padding space', function()
local node = i { '1234567890' }
assert.are.same(i { (' '):rep(2) .. '1234567890' }, util.center(node, 15))
end)
end)
describe('util.is_word', function()
it('can detect word', function()
for test, value in pairs {
['あうえお'] = false,
['hello'] = true,
[' hello'] = false,
['hello world'] = false,
['test_cool'] = false,
} do
assert.are.same(util.is_word(test), value)
end
end)
end)

100
lua/test/window_spec.lua Normal file
View File

@ -0,0 +1,100 @@
require 'test.setup'
describe('window', with_buffer(function(buffer)
local window
before_each(function()
buffer:wipe()
window = Trans.window.new {
buffer = buffer,
win_opts = {
col = 1,
row = 1,
width = 1,
height = 1,
relative = 'editor',
},
}
window:set('wrap', false)
end)
after_each(function()
window:try_close()
end)
it('can work well when no pass animation table', function()
window:open()
assert.is_true(api.nvim_win_is_valid(window.winid))
end)
describe('smooth_expand', function()
it('can work well when no pass animation table', function()
for field, values in pairs {
width = {
10,
6,
8,
5,
},
height = {
10,
6,
3,
},
} do
for _, value in ipairs(values) do
window:smooth_expand { field = field, to = value }
assert.are.same(value, window[field](window))
end
end
end)
it("don't change window wrap option", function()
window:smooth_expand { field = 'width', to = 10 }
assert.is_false(window:option 'wrap')
window:set('wrap', true)
window:smooth_expand { field = 'width', to = 10 }
assert.is_true(window:option 'wrap')
window:smooth_expand { field = 'height', to = 10 }
assert.is_true(window:option 'wrap')
end)
end)
it("resize() don't change window wrap option", function()
window:resize { width = 10, height = 10 }
assert.is_false(window:option 'wrap')
window:set('wrap', true)
window:resize { width = 5, height = 5 }
assert.is_true(window:option 'wrap')
end)
it('adjust_height() can auto adjust window height to buffer display height', function()
for idx, content in ipairs {
'cool',
'co10',
'家👍',
'👍ol',
'cあl',
'家野',
} do
buffer[idx] = content
end
local max_height = vim.o.lines - 2
for width, expect in ipairs {
[2] = 12,
[3] = 12,
[4] = 6,
[5] = 6,
} do
window:smooth_expand { field = 'width', to = width }
window:adjust_height()
assert.are.same(math.min(expect, max_height), window:height())
end
end)
end))

View File

@ -1,4 +1,4 @@
.PHONE: test
test:
nvim --headless --noplugin -u script/minimal_init.vim -c "PlenaryBustedDirectory lua/test/ { minimal_init = './scripts/minimal_init.vim' }" -c 'qa!'
nvim --headless --noplugin -u scripts/minimal_init.vim -c "PlenaryBustedDirectory lua/test/ { minimal_init = './scripts/minimal_init.vim' }" -c 'qa!'

View File

@ -1,34 +1,39 @@
local api, fn = vim.api, vim.fn
--- INFO :Define plugin command
local Trans = require("Trans")
local Trans = require 'Trans'
local command = api.nvim_create_user_command
command("Translate", function()
Trans.translate()
end, { desc = " Translate cursor word" })
command('Translate', function() Trans.translate() end,
{ desc = '󰊿 Translate cursor word' })
command("TranslateInput", function()
Trans.translate({ mode = 'i' })
end, { desc = " Translate input word" })
command('TranslateInput', function() Trans.translate { mode = 'i' } end,
{ desc = '󰊿 Translate input word' })
command("TransPlay", function()
command('TransPlay', function()
local util = Trans.util
local str = util.get_str(vim.fn.mode())
if str and str ~= "" and util.is_English(str) then
if str and str ~= '' and util.is_english(str) then
str:play()
end
end, { desc = " Auto play" })
end, { desc = ' Auto play' })
string.width = api.nvim_strwidth
local system = Trans.system
local f =
fn.has('linux') == 1 and ([[echo %q | festival --tts]])
or fn.has('mac') == 1 and ([[say %q]])
or 'node' .. Trans.relative_path { 'tts', 'say.js' } .. ' %q'
(vim.fn.has 'wsl' == 1 or system == 'win') and
'powershell.exe -Command "Add-Type -AssemblyName System.speech;(New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak(\\\"%s\\\")"' or
system == 'mac' and 'say %q' or
system == 'termux' and 'termux-tts-speak %q' or
system == 'linux' and 'echo %q | festival --tts' or
error 'Unsupported system'
string.play = function(self)
fn.jobstart(f:format(self))
---@diagnostic disable-next-line: param-type-mismatch
local s = string.gsub(self, '\"', ' ')
fn.jobstart(f:format(s))
end

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"say": "^0.16.0"
}
}

View File

@ -1,4 +0,0 @@
const say = require('say')
// console.log(word)
say.speak(process.argv.slice(2))