From 79348ec4c5831ebcf044155dfd547eced8f18a55 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Wed, 4 Jan 2023 22:22:52 +0800
Subject: [PATCH 01/17] test: rebuild this plugin

---
 lua/Trans/conf.lua      |  64 ++++-
 lua/Trans/database.lua  |  14 -
 lua/Trans/display.lua   | 601 +++++++++++++++++++++-------------------
 lua/Trans/highlight.lua |  26 --
 lua/Trans/setup.lua     |   7 +-
 lua/Trans/window.lua    |  48 ++++
 6 files changed, 419 insertions(+), 341 deletions(-)
 delete mode 100644 lua/Trans/highlight.lua
 create mode 100644 lua/Trans/window.lua

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

From c51937c6cf9aaa0a50334629c15992aab8dfb9ae Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Wed, 4 Jan 2023 23:06:09 +0800
Subject: [PATCH 02/17] fix: fix some bugs and need to refator this project

---
 lua/Trans/database.lua |  6 ------
 lua/Trans/init.lua     | 14 ++++++--------
 lua/Trans/setup.lua    | 22 +++++++++++-----------
 3 files changed, 17 insertions(+), 25 deletions(-)
 delete mode 100644 lua/Trans/database.lua

diff --git a/lua/Trans/database.lua b/lua/Trans/database.lua
deleted file mode 100644
index a5b77c0..0000000
--- a/lua/Trans/database.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local M = {}
-
-function M.query(arg)
-end
-
-return M
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 6a1a55f..909bd06 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -1,17 +1,15 @@
 local M = {}
 
-
 M.conf = require("Trans.conf")
 function M.setup(conf)
     conf = conf or {}
-    if conf.display then
-        conf.display = vim.tbl_extend('force', M.conf.display, conf.display)
+    for k, v in pairs(conf) do
+        if type(v) == 'table' then
+            M.conf[k] = vim.tbl_extend('force', M.conf[k], v)
+        else
+            M.conf[k] = v
+        end
     end
-
-    if conf.icon then
-        conf.icon = vim.tbl_extend('force', M.conf.icon, conf.icon)
-    end
-
     M.conf = vim.tbl_extend('force', M.conf, conf)
     require("Trans.setup")
 end
diff --git a/lua/Trans/setup.lua b/lua/Trans/setup.lua
index e0325b0..18d4e16 100644
--- a/lua/Trans/setup.lua
+++ b/lua/Trans/setup.lua
@@ -1,14 +1,17 @@
 local db = require("Trans").db
--- local conf = require("Trans").conf
 
-vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.display").query_cursor, {})
-vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.display").query_select, {})
-vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.display").query_input, {})
+vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.display").query_cursor, {
+    desc = '翻译光标下的单词',
+})
+vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.display").query_select, {
+    desc = '翻译选中的单词',
+})
+vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.display").query_input, {
+    desc = '翻译输入的单词',
+})
 
-
-local group = vim.api.nvim_create_augroup("Trans", { clear = true })
-vim.api.nvim_create_autocmd('VimLeave', {
-    group = group,
+vim.api.nvim_create_autocmd('VimLeavePre', {
+    group = vim.api.nvim_create_augroup("Trans", { clear = true }),
     pattern = '*',
     callback = function()
         if db:isopen() then
@@ -17,9 +20,6 @@ vim.api.nvim_create_autocmd('VimLeave', {
     end,
 })
 
--- vim.keymap.set('n', 'mm', '<cmd>TranslateCurosorWord<cr>')
--- vim.keymap.set('v', 'mm', '<Esc><cmd>TranslateSelectWord<cr>')
-
 local highlights = require("Trans").conf.highlight
 for highlight, opt in pairs(highlights) do
     vim.nvim_set_hl(0, highlight, opt)

From 409d85f615ac91712dcbcd212912ed78989d4a37 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Wed, 4 Jan 2023 23:11:19 +0800
Subject: [PATCH 03/17] feat: add conf to setup view for different command

---
 lua/Trans/conf.lua | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lua/Trans/conf.lua b/lua/Trans/conf.lua
index 493d001..fc61d66 100644
--- a/lua/Trans/conf.lua
+++ b/lua/Trans/conf.lua
@@ -69,7 +69,11 @@ return {
         notOxford = ''
     },
     auto_close = true,
-
+    style = {
+        input = 'float',
+        cursor = 'cursor',
+        select = 'cursor'
+    }
     -- TODO  add online translate engine
     -- online_search = {
     --     enable = false,

From 033622ed85f3b5f118abc3ab8b302888bca6e145 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Thu, 5 Jan 2023 16:24:50 +0800
Subject: [PATCH 04/17] feat: improve repository framework

---
 lua/Trans/conf.lua                  |  84 ---------------------
 lua/Trans/conf/base.lua             |  17 +++++
 lua/Trans/conf/default.lua          | 110 ++++++++++++++++++++++++++++
 lua/Trans/conf/init.lua             |   1 +
 lua/Trans/conf/loader.lua           |  52 +++++++++++++
 lua/Trans/conf/window.lua           |  52 +++++++++++++
 lua/Trans/content.lua               |   0
 lua/Trans/{display.lua => core.lua} |  11 +--
 lua/Trans/database/init.lua         |  29 ++++++++
 lua/Trans/init.lua                  |  26 ++-----
 lua/Trans/setup.lua                 |  22 ++----
 lua/Trans/util/debug.lua            |  35 +++++++++
 lua/Trans/window.lua                |  48 ------------
 lua/Trans/window/content.lua        |  18 +++++
 lua/Trans/window/display.lua        |  29 ++++++++
 lua/Trans/window/init.lua           |   0
 16 files changed, 357 insertions(+), 177 deletions(-)
 delete mode 100644 lua/Trans/conf.lua
 create mode 100644 lua/Trans/conf/base.lua
 create mode 100644 lua/Trans/conf/default.lua
 create mode 100644 lua/Trans/conf/init.lua
 create mode 100644 lua/Trans/conf/loader.lua
 create mode 100644 lua/Trans/conf/window.lua
 create mode 100644 lua/Trans/content.lua
 rename lua/Trans/{display.lua => core.lua} (97%)
 create mode 100644 lua/Trans/database/init.lua
 create mode 100644 lua/Trans/util/debug.lua
 delete mode 100644 lua/Trans/window.lua
 create mode 100644 lua/Trans/window/content.lua
 create mode 100644 lua/Trans/window/display.lua
 create mode 100644 lua/Trans/window/init.lua

diff --git a/lua/Trans/conf.lua b/lua/Trans/conf.lua
deleted file mode 100644
index fc61d66..0000000
--- a/lua/Trans/conf.lua
+++ /dev/null
@@ -1,84 +0,0 @@
-return {
-    view = {
-        cursor = {
-            -- NOTE :
-            -- 可选的风格:['fixed', 'relative', .. ]
-            style = 'fixed',
-            border = 'rounded',
-            -- NOTE :
-            -- 如果style设置为'relative'
-            -- 则其值代表最大限制, 设置为负数则无限制
-            width = 30,
-            height = 30,
-        },
-        float = {
-            top_offset = 1,
-            relative_width = 0.8,
-            border = 'rounded',
-        },
-    },
-    display = {
-        phnoetic = true,
-        collins_star = true,
-        oxford = true,
-        -- TODO
-        -- history = false,
-    },
-    order = {
-        'title',
-        'tag',
-        'pos',
-        'exchange',
-        'zh',
-        'en',
-    },
-
-    highligh = {
-        TransWord = {
-            fg = '#7ee787',
-            bold = true,
-        },
-        TransPhonetic = {
-            fg = '#8b949e',
-        },
-        TransRef = {
-            fg = '#75beff',
-            bold = true,
-        },
-        TransTag = {
-            fg = '#e5c07b',
-        },
-        TransExchange = {
-            link = 'TransTag',
-        },
-        TransPos = {
-            link = 'TransTag',
-        },
-        TransZh = {
-            link = 'TransWord',
-        },
-        TransEn = {
-            fg = '#bc8cff',
-        },
-    },
-    db_path = '$HOME/.vim/dict/ultimate.db',
-
-    icon = {
-        star = '⭐',
-        isOxford = '✔',
-        notOxford = ''
-    },
-    auto_close = true,
-    style = {
-        input = 'float',
-        cursor = 'cursor',
-        select = 'cursor'
-    }
-    -- TODO  add online translate engine
-    -- online_search = {
-    --     enable = false,
-    --     engine = {},
-    -- }
-
-    -- TODO register word
-}
diff --git a/lua/Trans/conf/base.lua b/lua/Trans/conf/base.lua
new file mode 100644
index 0000000..0a7f899
--- /dev/null
+++ b/lua/Trans/conf/base.lua
@@ -0,0 +1,17 @@
+local M = {}
+
+local buf_opts = {
+    filetype = 'Trans'
+}
+
+local buf = vim.api.nvim_create_buf(false, true)
+for k, v in pairs(buf_opts) do
+    vim.api.nvim_buf_set_options(buf, k, v)
+end
+
+M.buf = buf
+
+M.group = vim.api.nvim_create_augroup('Trans', { clear = true })
+
+
+return M
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
new file mode 100644
index 0000000..667274f
--- /dev/null
+++ b/lua/Trans/conf/default.lua
@@ -0,0 +1,110 @@
+local M = {}
+
+-- INFO :加载的规则 [LuaRule]
+M.replace_rules = {
+    'order',
+    'Trans.+',
+}
+
+M.conf = {
+    style = {
+        window = {
+            input = 'float',
+            cursor = 'cursor',
+            select = 'cursor'
+        },
+        order = {
+            'title',
+            'tag',
+            'pos',
+            'exchange',
+            'zh',
+            'en',
+        },
+        conf = {
+            -- NOTE :可选的风格:['fixed', 'relative', .. TODO]
+            -- width 和 height说明:
+            -- 大于1:
+                -- 如果style为fixed ,    则为固定的长宽
+                -- 如果style为relative , 则为最大长宽
+            -- 小于1:
+                -- 如果style为fixed ,    则为默认
+                -- 如果style为relative , 则为无限制
+            -- 0 ~ 1:
+                -- 相对长宽
+            cursor = {
+                style = 'fixed',
+                border = 'rounded',
+                width = 30,
+                height = 30,
+            },
+            float = {
+                style = 'fixed',
+                border = 'rounded',
+                width = 0.8,
+                height = 0.9,
+            },
+        },
+    },
+    ui = {
+        highligh = {
+            TransWord = {
+                fg = '#7ee787',
+                bold = true,
+            },
+            TransPhonetic = {
+                fg = '#8b949e',
+            },
+            TransRef = {
+                fg = '#75beff',
+                bold = true,
+            },
+            TransTag = {
+                fg = '#e5c07b',
+            },
+            TransExchange = {
+                link = 'TransTag',
+            },
+            TransPos = {
+                link = 'TransTag',
+            },
+            TransZh = {
+                link = 'TransWord',
+            },
+            TransEn = {
+                fg = '#bc8cff',
+            },
+        },
+        icon = {
+            star = '⭐',
+            isOxford = '✔',
+            notOxford = ''
+        },
+        display = {
+            phnoetic = true,
+            collins_star = true,
+            oxford = true,
+            -- TODO
+            -- history = false,
+        },
+    },
+    base = {
+        db_path = '$HOME/.vim/dict/ultimate.db',
+        auto_close = true,
+        lazy_load = false,
+        debug = {
+            enable = true,
+            type_check = true,
+            unknown_conf = true,
+        },
+    },
+    -- TODO  add online translate engine
+    -- online_search = {
+    --     enable = false,
+    --     engine = {},
+    -- }
+
+    -- TODO register word
+}
+
+return M
diff --git a/lua/Trans/conf/init.lua b/lua/Trans/conf/init.lua
new file mode 100644
index 0000000..01baf8e
--- /dev/null
+++ b/lua/Trans/conf/init.lua
@@ -0,0 +1 @@
+return require("Trans.conf.loader").get_conf()
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
new file mode 100644
index 0000000..7ccad44
--- /dev/null
+++ b/lua/Trans/conf/loader.lua
@@ -0,0 +1,52 @@
+---@diagnostic disable: unused-local, unused-function
+local M = {}
+
+local replace_rules = require("Trans.conf.default").replace_rules
+local conf          = require("Trans.conf.default").conf
+local user_conf     = require("Trans").conf
+local type_check    = require("Trans.util.debug").type_check
+local is_loaded = false
+
+local function need_extend(name)
+    type_check {
+        name = { name, 'string' }
+    }
+    for _, rule in ipairs(replace_rules) do
+        if name:match(rule) then
+            return false
+        end
+    end
+    return true
+end
+
+-- 加载用户自定义的配置
+---@param t1 table
+---@param t2 table
+local function extend(t1, t2)
+    type_check {
+        t1 = { t1, 'table' },
+        t2 = { t2, 'table' },
+    }
+    for k, v in pairs(t2) do
+        if type(v) == 'table' and need_extend(k) then
+            extend(t1[k], v)
+        else
+            t1[k] = v
+        end
+    end
+end
+
+M.get_conf = function()
+    if not is_loaded then
+        M.load_conf()
+    end
+    return conf
+end
+
+M.load_conf = function()
+    -- loaded_conf = default_conf:extend(user_conf)
+    extend(conf, user_conf)
+    is_loaded = true
+end
+
+return M
diff --git a/lua/Trans/conf/window.lua b/lua/Trans/conf/window.lua
new file mode 100644
index 0000000..6f49f3f
--- /dev/null
+++ b/lua/Trans/conf/window.lua
@@ -0,0 +1,52 @@
+local M = {}
+local conf = require("Trans").conf.view
+
+local get_float_opts = function(float_conf)
+    local columns = vim.o.columns
+    local height = vim.o.lines - vim.o.cmdheight - float_conf.top_offset
+    local width = math.floor(columns * float_conf.relative_width)
+
+    return {
+        relative = 'editor',
+        col = math.floor((columns - width) / 2), -- 两侧的宽度
+        row = float_conf.top_offset,
+        title = 'Trans',
+        title_pos = 'center',
+        style = 'minimal',
+        width = width,
+        height = height,
+        border = float_conf.border,
+        zindex = 50,
+    }
+end
+
+local get_cursor_opts = function(cursor_conf)
+    local opts = {
+        relative = 'cursor',
+        col = 2,
+        row = 2,
+        title = 'Trans',
+        title_pos = 'center',
+        style = 'minimal',
+        border = cursor_conf.border,
+        -- TODO keymap to convert style to Float
+        focusable = false,
+        zindex = 100,
+    }
+    if cursor_conf.style == 'fixed' then
+        opts.width = cursor_conf.width
+        opts.height = cursor_conf.height
+    elseif cursor_conf.style == 'relative' then
+        opts.width = (cursor_conf.width > 0 and conf.width < conf.max_width) and conf.width or conf.max_width
+        opts.height = (cursor_conf.height > 0 and conf.height < conf.max_height) and conf.height or conf.max_height
+    else
+        error('unknown style!')
+    end
+    return opts
+end
+
+M.get_float_opts = get_float_opts(conf.float)
+
+M.cursor_opts = get_cursor_opts(conf.cursor)
+
+return M
diff --git a/lua/Trans/content.lua b/lua/Trans/content.lua
new file mode 100644
index 0000000..e69de29
diff --git a/lua/Trans/display.lua b/lua/Trans/core.lua
similarity index 97%
rename from lua/Trans/display.lua
rename to lua/Trans/core.lua
index 2b41cca..08676d6 100644
--- a/lua/Trans/display.lua
+++ b/lua/Trans/core.lua
@@ -8,9 +8,6 @@ local order      = conf.order
 local auto_close = conf.auto_close
 local view       = conf.view
 
--- TODO : setup database
-local db_path = require("Trans").conf.db_path
-local dict = require("Trans").db:open(db_path)
 
 local highlight = {
     word     = 'TransWord',
@@ -23,6 +20,7 @@ local highlight = {
     en       = 'TransEn',
 }
 
+
 local function get_select()
     local s_start = vim.fn.getpos("'<")
     local s_end = vim.fn.getpos("'>")
@@ -46,12 +44,7 @@ local function get_query_res(method)
     else
         error('unknown method')
     end
-
-    -- TODO : dict query optimization
-    local res = dict:select('stardict', {
-        where = { word = arg },
-    })
-    return res[1]
+    -- FIXME 
 end
 
 M.TransLate = function(opts)
diff --git a/lua/Trans/database/init.lua b/lua/Trans/database/init.lua
new file mode 100644
index 0000000..a20baf6
--- /dev/null
+++ b/lua/Trans/database/init.lua
@@ -0,0 +1,29 @@
+local M = {}
+local _, db = pcall(require, 'sqlite.db')
+if not _ then
+    error('Please check out sqlite.lua')
+end
+
+-- INFO : init database
+local path = require("Trans").conf.db_path
+local dict = db:open(path)
+
+-- INFO :Auto Close
+vim.api.nvim_create_autocmd('VimLeavePre', {
+    group = require("Trans.conf.base").autogroup,
+    callback = function ()
+        if db:isopen() then
+            db:close()
+        end
+    end
+})
+
+M.query = function (arg)
+    -- TODO : more opts
+    local res = dict:select('stardict', {
+        where = { word = arg },
+    })
+    return res[1]
+end
+
+return M
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 909bd06..828a1be 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -1,29 +1,13 @@
 local M = {}
 
-M.conf = require("Trans.conf")
+M.conf = {}
+
 function M.setup(conf)
-    conf = conf or {}
-    for k, v in pairs(conf) do
-        if type(v) == 'table' then
-            M.conf[k] = vim.tbl_extend('force', M.conf[k], v)
-        else
-            M.conf[k] = v
-        end
+    M.conf = conf or {}
+    if conf.base and not conf.base.lazy_load then
+        require("Trans.conf.loader").load_conf()
     end
-    M.conf = vim.tbl_extend('force', M.conf, conf)
     require("Trans.setup")
 end
 
-local res = vim.fn.executable('sqlite3')
-if res ~= 1 then
-    error('Please check out sqlite3')
-end
-
-local status, db = pcall(require, 'sqlite.db')
-if not status then
-    error('Please check out sqlite.lua')
-end
-
-M.db = db
-
 return M
diff --git a/lua/Trans/setup.lua b/lua/Trans/setup.lua
index 18d4e16..9bf3250 100644
--- a/lua/Trans/setup.lua
+++ b/lua/Trans/setup.lua
@@ -1,26 +1,18 @@
-local db = require("Trans").db
+if vim.fn.executable('sqlite3') ~= 1 then
+    error('Please check out sqlite3')
+end
 
-vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.display").query_cursor, {
+vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.core").query_cursor, {
     desc = '翻译光标下的单词',
 })
-vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.display").query_select, {
+vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.core").query_select, {
     desc = '翻译选中的单词',
 })
-vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.display").query_input, {
+vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.core").query_input, {
     desc = '翻译输入的单词',
 })
 
-vim.api.nvim_create_autocmd('VimLeavePre', {
-    group = vim.api.nvim_create_augroup("Trans", { clear = true }),
-    pattern = '*',
-    callback = function()
-        if db:isopen() then
-            db:close()
-        end
-    end,
-})
-
-local highlights = require("Trans").conf.highlight
+local highlights = require("Trans.conf").ui.highligh
 for highlight, opt in pairs(highlights) do
     vim.nvim_set_hl(0, highlight, opt)
 end
diff --git a/lua/Trans/util/debug.lua b/lua/Trans/util/debug.lua
new file mode 100644
index 0000000..874954b
--- /dev/null
+++ b/lua/Trans/util/debug.lua
@@ -0,0 +1,35 @@
+local M = {}
+
+-- INFO : get loaded debug conf
+local base = require("Trans").conf.base
+local debug = require("Trans.conf.default").conf.base.debug
+if base and base.debug then
+    debug = vim.tbl_extend('force', debug, base)
+end
+
+M.type_check = function (types)
+    if debug.enable and debug.type_check then
+        vim.validate(types)
+    end
+end
+-- local function dedent(lines)
+--     local ind_size = math.huge
+--     for i, _ in ipairs(lines) do
+--         local i1, i2 = lines[i]:find("^%s*[^%s]")
+--         if i1 and i2 < ind_size then
+--             ind_size = i2
+--         end
+--     end
+--     for i, _ in ipairs(lines) do
+--         lines[i] = lines[i]:sub(ind_size, -1)
+--     end
+-- end
+--
+-- function M.dedent(s)
+--     local lst = vim.split(s, "\n")
+--     dedent(lst)
+--     return table.concat(lst, "\n")
+-- end
+
+
+return M
diff --git a/lua/Trans/window.lua b/lua/Trans/window.lua
deleted file mode 100644
index e02eb5c..0000000
--- a/lua/Trans/window.lua
+++ /dev/null
@@ -1,48 +0,0 @@
--- TODO  different style to display
-local M = {}
-
-M.float_opts = function(conf)
-    local columns = vim.o.columns
-    local height = vim.o.lines - vim.o.cmdheight - conf.top_offset
-    local width = math.floor(columns * conf.relative_width)
-
-    return {
-        relative = 'editor',
-        col = math.floor((columns - width) / 2), -- 两侧的宽度
-        row = conf.top_offset,
-        title = 'Trans',
-        title_pos = 'center',
-        style = 'minimal',
-        width = width,
-        height = height,
-        border = conf.border,
-        zindex = 50,
-    }
-end
-
-M.cursor_opts = function (conf)
-    local opts = {
-        relative = 'cursor',
-        col = 2,
-        row = 2,
-        title = 'Trans',
-        title_pos = 'center',
-        style = 'minimal',
-        border = conf.border,
-        -- TODO keymap to convert style to Float
-        focusable = false,
-        zindex = 100,
-    }
-    if conf.style == 'fixed' then
-        opts.width = conf.width
-        opts.height = conf.height
-    elseif conf.style == 'relative' then
-        opts.width = (conf.width > 0 and conf.width < conf.max_width) and conf.width  or conf.max_width
-        opts.height = (conf.height > 0 and conf.height < conf.max_height) and conf.height  or conf.max_height
-    else
-        error('unknown style!')
-    end
-    return opts
-end
-
-return M
diff --git a/lua/Trans/window/content.lua b/lua/Trans/window/content.lua
new file mode 100644
index 0000000..1b86632
--- /dev/null
+++ b/lua/Trans/window/content.lua
@@ -0,0 +1,18 @@
+local M = {}
+
+--[[
+content = {
+    lines = {}          ---@type string[]
+    highlight = {}
+}
+--]]
+---@param contents string[]
+M.set = function (win, contents)
+    vim.validate {
+        contents = { contents, 'table' },
+    }
+    -- TODO 
+end
+
+
+return M
diff --git a/lua/Trans/window/display.lua b/lua/Trans/window/display.lua
new file mode 100644
index 0000000..567149b
--- /dev/null
+++ b/lua/Trans/window/display.lua
@@ -0,0 +1,29 @@
+local M = {}
+local api = vim.api
+local util = require("Trans.window.util")
+M.buf = util.init_buf()
+
+--- 浮动窗口的风格
+---@param conf table 自定义配置
+M.show_float_win = function(conf)
+    vim.validate {
+        conf = { conf, 'table' },
+    }
+    local opts = util.get_float_opts(conf)
+    local win = api.nvim_open_win(M.buf, true, opts)
+    return win
+end
+
+M.show_cursor_win = function(conf)
+    vim.validate {
+        conf = { conf, 'table' },
+    }
+    local opts = util.get_cursor_opts(conf)
+    local win = api.nvim_open_win(M.buf, true, opts)
+    return win
+end
+
+-- TODO <++> more window style
+
+
+return M
diff --git a/lua/Trans/window/init.lua b/lua/Trans/window/init.lua
new file mode 100644
index 0000000..e69de29

From a1488b2d9b75691a33e40232c37b4be541749d81 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Thu, 5 Jan 2023 21:15:01 +0800
Subject: [PATCH 05/17] refactor: init the repo and decide to add more feature

---
 lua/.luarc.json                             |  6 ++++
 lua/Trans/component/offline/Definition.lua  |  7 ++++
 lua/Trans/component/offline/Exchange.lua    |  7 ++++
 lua/Trans/component/offline/Pos.lua         |  7 ++++
 lua/Trans/component/offline/Tag.lua         |  7 ++++
 lua/Trans/component/offline/Title.lua       |  7 ++++
 lua/Trans/component/offline/Translation.lua |  7 ++++
 lua/Trans/conf/base.lua                     |  2 +-
 lua/Trans/conf/default.lua                  | 34 +++++++++++--------
 lua/Trans/conf/window.lua                   | 11 +++++-
 lua/Trans/core/content.lua                  | 19 +++++++++++
 lua/Trans/{core.lua => core/init.lua}       | 25 --------------
 lua/Trans/core/query.lua                    | 37 +++++++++++++++++++++
 lua/Trans/database/init.lua                 | 27 ++++++++++++---
 lua/Trans/init.lua                          |  2 +-
 lua/Trans/{content.lua => ui/init.lua}      |  0
 lua/Trans/util/parser.lua                   | 19 +++++++++++
 17 files changed, 178 insertions(+), 46 deletions(-)
 create mode 100644 lua/.luarc.json
 create mode 100644 lua/Trans/component/offline/Definition.lua
 create mode 100644 lua/Trans/component/offline/Exchange.lua
 create mode 100644 lua/Trans/component/offline/Pos.lua
 create mode 100644 lua/Trans/component/offline/Tag.lua
 create mode 100644 lua/Trans/component/offline/Title.lua
 create mode 100644 lua/Trans/component/offline/Translation.lua
 create mode 100644 lua/Trans/core/content.lua
 rename lua/Trans/{core.lua => core/init.lua} (91%)
 create mode 100644 lua/Trans/core/query.lua
 rename lua/Trans/{content.lua => ui/init.lua} (100%)
 create mode 100644 lua/Trans/util/parser.lua

diff --git a/lua/.luarc.json b/lua/.luarc.json
new file mode 100644
index 0000000..43e8c9f
--- /dev/null
+++ b/lua/.luarc.json
@@ -0,0 +1,6 @@
+{
+    "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
+    "Lua.diagnostics.disable": [
+        "unused-local"
+    ]
+}
\ No newline at end of file
diff --git a/lua/Trans/component/offline/Definition.lua b/lua/Trans/component/offline/Definition.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Definition.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/component/offline/Exchange.lua b/lua/Trans/component/offline/Exchange.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Exchange.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/component/offline/Pos.lua b/lua/Trans/component/offline/Pos.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Pos.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/component/offline/Tag.lua b/lua/Trans/component/offline/Tag.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Tag.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Title.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/component/offline/Translation.lua b/lua/Trans/component/offline/Translation.lua
new file mode 100644
index 0000000..cf04e60
--- /dev/null
+++ b/lua/Trans/component/offline/Translation.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.to_lines = function (field)
+    -- TODO 
+end
+
+return M
diff --git a/lua/Trans/conf/base.lua b/lua/Trans/conf/base.lua
index 0a7f899..42c4d8e 100644
--- a/lua/Trans/conf/base.lua
+++ b/lua/Trans/conf/base.lua
@@ -6,7 +6,7 @@ local buf_opts = {
 
 local buf = vim.api.nvim_create_buf(false, true)
 for k, v in pairs(buf_opts) do
-    vim.api.nvim_buf_set_options(buf, k, v)
+    vim.api.nvim_buf_set_option(buf, k, v)
 end
 
 M.buf = buf
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 667274f..7212202 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -1,27 +1,21 @@
 local M = {}
 
--- INFO :加载的规则 [LuaRule]
-M.replace_rules = {
-    'order',
-    'Trans.+',
-}
-
 M.conf = {
     style = {
-        window = {
+        ui = {
             input = 'float',
             cursor = 'cursor',
             select = 'cursor'
         },
         order = {
-            'title',
-            'tag',
-            'pos',
-            'exchange',
-            'zh',
-            'en',
+            'Title',
+            'Tag',
+            'Pos',
+            'Exchange',
+            'Translation',
+            'Definition',
         },
-        conf = {
+        window = {
             -- NOTE :可选的风格:['fixed', 'relative', .. TODO]
             -- width 和 height说明:
             -- 大于1:
@@ -44,6 +38,12 @@ M.conf = {
                 width = 0.8,
                 height = 0.9,
             },
+            -- NOTE :如果你想限制某个组件的行数,可以设置 (名称与order相同)
+            -- Example:
+            -- limit = {
+            --     En = 1, -- 只显示第一行,(一般为最广泛的释义)
+            -- },
+            limit = nil, 
         },
     },
     ui = {
@@ -107,4 +107,10 @@ M.conf = {
     -- TODO register word
 }
 
+-- INFO :加载的规则 [LuaRule]
+M.replace_rules = {
+    'order',
+    'Trans.+',
+}
+
 return M
diff --git a/lua/Trans/conf/window.lua b/lua/Trans/conf/window.lua
index 6f49f3f..04c6b49 100644
--- a/lua/Trans/conf/window.lua
+++ b/lua/Trans/conf/window.lua
@@ -1,7 +1,13 @@
 local M = {}
-local conf = require("Trans").conf.view
+local conf = require("Trans.conf").style.window
+local type_check = require("Trans.util.debug").type_check
+
+-- FIXME 
 
 local get_float_opts = function(float_conf)
+    type_check {
+        float_conf = { float_conf, 'table' },
+    }
     local columns = vim.o.columns
     local height = vim.o.lines - vim.o.cmdheight - float_conf.top_offset
     local width = math.floor(columns * float_conf.relative_width)
@@ -21,6 +27,9 @@ local get_float_opts = function(float_conf)
 end
 
 local get_cursor_opts = function(cursor_conf)
+    type_check {
+        cursor_conf = { cursor_conf, 'table' },
+    }
     local opts = {
         relative = 'cursor',
         col = 2,
diff --git a/lua/Trans/core/content.lua b/lua/Trans/core/content.lua
new file mode 100644
index 0000000..0cc6206
--- /dev/null
+++ b/lua/Trans/core/content.lua
@@ -0,0 +1,19 @@
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+
+local offline_dir = debug.getinfo(1, "S").source:sub(2):match('.*Trans') .. '/component/offline'
+
+M.to_content = function(query_res)
+    type_check {
+        query_res = { query_res, 'table' }
+    }
+    local content = {}
+    for file in vim.fs.dir(offline_dir) do
+        local res = require("Trans.component.offline." .. file:gsub('.lua', '')).to_content(query_res)
+        assert(res)
+        table.insert(content, res)
+    end
+    return content
+end
+
+return M
diff --git a/lua/Trans/core.lua b/lua/Trans/core/init.lua
similarity index 91%
rename from lua/Trans/core.lua
rename to lua/Trans/core/init.lua
index 08676d6..6e28f2d 100644
--- a/lua/Trans/core.lua
+++ b/lua/Trans/core/init.lua
@@ -1,4 +1,3 @@
----@diagnostic disable: unused-local
 local M          = {}
 local api        = vim.api
 local conf       = require("Trans").conf
@@ -21,31 +20,7 @@ local highlight = {
 }
 
 
-local function get_select()
-    local s_start = vim.fn.getpos("'<")
-    local s_end = vim.fn.getpos("'>")
-    if s_start[2] ~= s_start[2] then
-        error('TODO: multiline translate')
-    end
-    local lin = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)[1]
-    local word = string.sub(lin, s_start[3], s_end[3])
-    return word
-end
 
-local function get_query_res(method)
-    -- NOTE : get query word
-    local word = ''
-    if method == 'cursor' then
-        word = vim.fn.expand('<cword>')
-    elseif method == 'select' then
-        word = get_select():match('%s+')
-    elseif method == 'input' then
-        word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
-    else
-        error('unknown method')
-    end
-    -- FIXME 
-end
 
 M.TransLate = function(opts)
     local res = get_query_res(opts.method)
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
new file mode 100644
index 0000000..2f3f43e
--- /dev/null
+++ b/lua/Trans/core/query.lua
@@ -0,0 +1,37 @@
+local M = {}
+
+local type_check = require("Trans.util.debug").type_check
+local query = require("Trans.database").query
+
+local function get_select()
+    local s_start = vim.fn.getpos("'<")
+    local s_end = vim.fn.getpos("'>")
+    if s_start[2] ~= s_start[2] then
+        error('TODO: multiline translate')
+    end
+    local lin = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)[1]
+    local word = string.sub(lin, s_start[3], s_end[3])
+    return word
+end
+
+M.get_query_res = function(method)
+    type_check {
+        method = { method, 'string' },
+    }
+
+    -- NOTE : get query word
+    local word = ''
+    if method == 'cursor' then
+        word = vim.fn.expand('<cword>')
+    elseif method == 'select' then
+        word = get_select():match('%s+')
+    elseif method == 'input' then
+        word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
+    else
+        error('unknown method')
+    end
+    -- FIXME
+    return query(word)
+end
+
+return M
diff --git a/lua/Trans/database/init.lua b/lua/Trans/database/init.lua
index a20baf6..aeab460 100644
--- a/lua/Trans/database/init.lua
+++ b/lua/Trans/database/init.lua
@@ -3,25 +3,44 @@ local _, db = pcall(require, 'sqlite.db')
 if not _ then
     error('Please check out sqlite.lua')
 end
+local type_check = require("Trans.util.debug").type_check
+
+local query_field = {
+    'word',
+    'phonetic',
+    'definition',
+    'translation',
+    'pos',
+    'collins',
+    'oxford',
+    'tag',
+    'exchange',
+}
 
 -- INFO : init database
-local path = require("Trans").conf.db_path
+local path = require("Trans.conf").base.db_path
 local dict = db:open(path)
 
 -- INFO :Auto Close
 vim.api.nvim_create_autocmd('VimLeavePre', {
     group = require("Trans.conf.base").autogroup,
-    callback = function ()
+    callback = function()
         if db:isopen() then
             db:close()
         end
     end
 })
 
-M.query = function (arg)
+M.query = function(arg)
     -- TODO : more opts
+    type_check {
+        arg = { arg, 'string' },
+    }
     local res = dict:select('stardict', {
-        where = { word = arg },
+        where = {
+            word = arg,
+        },
+        keys = query_field,
     })
     return res[1]
 end
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 828a1be..e076815 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -7,7 +7,7 @@ function M.setup(conf)
     if conf.base and not conf.base.lazy_load then
         require("Trans.conf.loader").load_conf()
     end
-    require("Trans.setup")
+    -- require("Trans.setup")
 end
 
 return M
diff --git a/lua/Trans/content.lua b/lua/Trans/ui/init.lua
similarity index 100%
rename from lua/Trans/content.lua
rename to lua/Trans/ui/init.lua
diff --git a/lua/Trans/util/parser.lua b/lua/Trans/util/parser.lua
new file mode 100644
index 0000000..4c4adfc
--- /dev/null
+++ b/lua/Trans/util/parser.lua
@@ -0,0 +1,19 @@
+---@diagnostic disable: missing-return, unused-local
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+
+---解析宽度
+---@param width integer
+---@return integer
+M.width = function (width)
+    -- TODO 
+end
+
+---解析宽度
+---@param height integer
+---@return integer
+M.height = function (height)
+    -- TODO 
+end
+
+return M

From 2f6520940a3d0b0c675b262c0ef99a7c248f9327 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Fri, 6 Jan 2023 23:05:10 +0800
Subject: [PATCH 06/17] feat: add Trans.util.test.query_youdao file ,.. and
 some utility function

---
 lua/Trans/component/offline/Definition.lua  |   2 +-
 lua/Trans/component/offline/Exchange.lua    |   2 +-
 lua/Trans/component/offline/Pos.lua         |   2 +-
 lua/Trans/component/offline/Tag.lua         |   2 +-
 lua/Trans/component/offline/Title.lua       |  26 +++-
 lua/Trans/component/offline/Translation.lua |   2 +-
 lua/Trans/conf/default.lua                  |  17 +--
 lua/Trans/util/format.lua                   | 124 ++++++++++++++++++++
 lua/Trans/util/test/a.lua                   |   1 +
 lua/Trans/util/test/query_youdao.lua        |  66 +++++++++++
 10 files changed, 225 insertions(+), 19 deletions(-)
 create mode 100644 lua/Trans/util/format.lua
 create mode 120000 lua/Trans/util/test/a.lua
 create mode 100644 lua/Trans/util/test/query_youdao.lua

diff --git a/lua/Trans/component/offline/Definition.lua b/lua/Trans/component/offline/Definition.lua
index cf04e60..94acd96 100644
--- a/lua/Trans/component/offline/Definition.lua
+++ b/lua/Trans/component/offline/Definition.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_lines = function (field)
+M.to_content = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Exchange.lua b/lua/Trans/component/offline/Exchange.lua
index cf04e60..94acd96 100644
--- a/lua/Trans/component/offline/Exchange.lua
+++ b/lua/Trans/component/offline/Exchange.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_lines = function (field)
+M.to_content = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Pos.lua b/lua/Trans/component/offline/Pos.lua
index cf04e60..94acd96 100644
--- a/lua/Trans/component/offline/Pos.lua
+++ b/lua/Trans/component/offline/Pos.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_lines = function (field)
+M.to_content = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Tag.lua b/lua/Trans/component/offline/Tag.lua
index cf04e60..94acd96 100644
--- a/lua/Trans/component/offline/Tag.lua
+++ b/lua/Trans/component/offline/Tag.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_lines = function (field)
+M.to_content = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index cf04e60..71d3068 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -1,7 +1,31 @@
 local M = {}
 
-M.to_lines = function (field)
+local display = require("Tran.conf").ui.display
+-- Example:
+-- local content = {
+--     width = 1,
+--     height = 1;
+--     lines = {
+--         Highlight = {
+--             'first line',
+--             'second line',
+--         }
+--     },   ---@table
+-- }
+
+
+-- local function format()
+--     
+-- end
+
+M.to_content = function (field)
     -- TODO 
+    local line = ''
+    local format = '%s  %s %s %s'
+    local content = {
+        height = 1,
+    }
+    return content
 end
 
 return M
diff --git a/lua/Trans/component/offline/Translation.lua b/lua/Trans/component/offline/Translation.lua
index cf04e60..94acd96 100644
--- a/lua/Trans/component/offline/Translation.lua
+++ b/lua/Trans/component/offline/Translation.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_lines = function (field)
+M.to_content = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 7212202..80d8694 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -16,24 +16,12 @@ M.conf = {
             'Definition',
         },
         window = {
-            -- NOTE :可选的风格:['fixed', 'relative', .. TODO]
-            -- width 和 height说明:
-            -- 大于1:
-                -- 如果style为fixed ,    则为固定的长宽
-                -- 如果style为relative , 则为最大长宽
-            -- 小于1:
-                -- 如果style为fixed ,    则为默认
-                -- 如果style为relative , 则为无限制
-            -- 0 ~ 1:
-                -- 相对长宽
             cursor = {
-                style = 'fixed',
                 border = 'rounded',
                 width = 30,
                 height = 30,
             },
             float = {
-                style = 'fixed',
                 border = 'rounded',
                 width = 0.8,
                 height = 0.9,
@@ -43,7 +31,7 @@ M.conf = {
             -- limit = {
             --     En = 1, -- 只显示第一行,(一般为最广泛的释义)
             -- },
-            limit = nil, 
+            limit = nil,
         },
     },
     ui = {
@@ -98,6 +86,9 @@ M.conf = {
             unknown_conf = true,
         },
     },
+    map = {
+        -- TODO
+    },
     -- TODO  add online translate engine
     -- online_search = {
     --     enable = false,
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
new file mode 100644
index 0000000..7d9bf80
--- /dev/null
+++ b/lua/Trans/util/format.lua
@@ -0,0 +1,124 @@
+---@diagnostic disable: undefined-global
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+
+-- 各种风格的基础宽度
+local style_width = {
+    float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
+    cursor = require("Trans.conf.window").cursor.width,
+}
+
+local m_width  = nil -- 需要被格式化窗口的高度
+local m_fields = nil -- 待格式化的字段
+local m_indent = nil -- 每行的行首缩进
+local m_length = nil -- 所有字段加起来的长度(不包括缩进和间隔)
+
+local function get_rows()
+    -- TODO
+    return rows
+end
+
+local function do_indent(lines)
+    for i, v in ipairs(lines) do
+        lines[i] = (' '):rep(m_indent) .. v
+    end
+end
+
+local function format_to_line()
+    local space = math.floor((m_width - m_length) / #m_fields)
+    return line
+end
+
+local function format_to_multilines()
+    -- TODO
+    type_check {
+        interval = { interval, 'number' },
+        rows     = { rows, 'number' },
+    }
+end
+
+local function get_formatted_lines()
+    local lines = {}
+    -- NOTE : 判断能否格式化成一行
+    if m_length + (#m_fields * m_indent) > m_width then
+        lines = format_to_multilines()
+    else
+        lines[1] = format_to_line()
+    end
+
+    if m_indent then
+        do_indent(lines)
+    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)
+    if not fields then
+        return {}
+    end
+    type_check {
+        style = { style, { 'string' } },
+        fields = { fields, { 'table' } },
+        indent = { indent, { 'number' }, true },
+    }
+
+    local length = 0
+    for _, v in ipairs(fields) do
+        length = length + #v
+    end
+
+    m_width      = style_width[style] - indent
+    m_indent     = indent
+    m_fields = fields
+    m_length = length
+    return get_formatted_lines()
+end
+
+-- local function get_lines(win_width, components)
+--     local lines = {}
+--     local interval = win_width > 40 and 6 or 4
+--     local row = 1
+--     local width = win_width - #components[1]
+--     for i in 2, #components do
+--         width = width - #components[i] - interval
+--         if width < 0 then
+--             width = win_width - #components[i]
+--             row = row + 1
+--         end
+--     end
+--     if row == 1 then
+--         local format = '%s' .. ((' '):rep(interval) .. '%s')
+--         lines[1] = string.format(format, unpack(components))
+--     else
+--         table.sort(components, function (a, b)
+--             return #a > #b
+--         end)
+--         -- FIXME
+--         local res, rem = #components / (row + 1), #components % (row + 1)
+--         row = math.ceil(res)
+--         local rol = row - rem - 1
+--     end
+--
+--     return lines
+-- end
+--
+-- M.format = function(style, components, indent)
+--     local lines = {}
+--     if #components > 1 then
+--         indent = indent or 0
+--         type_check {
+--             style = { style, 'string' },
+--             components = { components, 'table' }, ---@string[]
+--             -- max_items = { max_items, { 'nil', 'number' } }, ---@string[]
+--         }
+--         local win_width = (style == 'float' and float_win_width or cursor_win_width) - indent
+--         local res = get_lines(win_width, components)
+--     end
+--     return lines
+-- end
+return M
diff --git a/lua/Trans/util/test/a.lua b/lua/Trans/util/test/a.lua
new file mode 120000
index 0000000..9b39cbe
--- /dev/null
+++ b/lua/Trans/util/test/a.lua
@@ -0,0 +1 @@
+query_youdao.lua
\ No newline at end of file
diff --git a/lua/Trans/util/test/query_youdao.lua b/lua/Trans/util/test/query_youdao.lua
new file mode 100644
index 0000000..1d064f8
--- /dev/null
+++ b/lua/Trans/util/test/query_youdao.lua
@@ -0,0 +1,66 @@
+local M = {}
+-- local type_check = require("Trans.util.debug").type_check
+local salt = '96836db9-1e28-4789-b5a6-fb7bb67e1259'
+local appKey = '1858465a8708c121'
+local appPasswd = 'fG0sitfk16nJOlIlycnLPYZn1optxUxL'
+
+local curtime
+local word
+
+local function caculate_input()
+    local input
+    local len = #word
+    if len > 20 then
+        input = word:sub(1, 10) .. len .. word:sub(-10)
+    else
+        input = word
+    end
+    return input
+end
+
+local function caculate_sign()
+    -- sign=sha256(应用ID+input+salt+curtime+应用密钥);
+    local hash = appKey .. caculate_input() .. salt .. curtime .. appPasswd
+
+    return vim.fn.sha256(hash)
+end
+
+local function test()
+    local query = {
+        q        = word,
+        from     = 'auto',
+        to       = 'zh-CHS',
+        -- dicts    = 'ec',
+        signType = 'v3',
+        appKey   = appKey,
+        salt     = salt,
+        curtime  = curtime,
+        sign     = caculate_sign(),
+    }
+    return query
+end
+
+-- curl --data {{'{"name":"bob"}'}} --header {{'Content-Type: application/json'}} {{http://example.com/users/1234}}
+
+local function query_word(q)
+    local field = (
+        [[curl -s --header 'Content-Type: application/x-www-form-urlencoded' https://openapi.youdao.com/api]])
+    for k, v in pairs(q) do
+        field = field .. ([[ -d '%s=%s']]):format(k, v)
+    end
+    -- vim.pretty_print(field)
+    local output = vim.fn.system(field)
+    local tb = vim.fn.json_decode(output)
+    -- print(type(output))
+    -- vim.pretty_print(tb.basic)
+end
+
+M.test = function(query)
+    curtime = tostring(os.time()) -- 更新一下time
+    word = query or 'as'
+    -- local json = vim.fn.json_encode(test())
+    query_word(test())
+    -- vim.pretty_print(vim.fn.json_encode(json))
+end
+
+return M

From 5a424c66bb106b2d6cea77ae1793d2ca34a01169 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Sun, 8 Jan 2023 15:07:12 +0800
Subject: [PATCH 07/17] feat: add format utility function and improve loader
 method

---
 go/go.mod                             |   3 +
 go/query_online.go                    |  50 +++++++
 lua/.luarc.json                       |   3 +-
 lua/Trans/component/init.lua          |   8 +
 lua/Trans/component/offline/Title.lua |   2 +-
 lua/Trans/conf/default.lua            |  38 +++--
 lua/Trans/conf/init.lua               |   1 -
 lua/Trans/conf/loader.lua             |  76 +++++-----
 lua/Trans/conf/window.lua             |   2 +-
 lua/Trans/database/init.lua           |   2 +-
 lua/Trans/init.lua                    |   8 +-
 lua/Trans/util/debug.lua              |   2 +-
 lua/Trans/util/format.lua             | 196 ++++++++++++++----------
 lua/Trans/util/test/a.lua             |   1 -
 lua/Trans/util/test/format.lua        | 205 ++++++++++++++++++++++++++
 lua/Trans/util/test/is_Chinese.lua    |  15 ++
 lua/Trans/util/test/test.lua          |  13 ++
 17 files changed, 486 insertions(+), 139 deletions(-)
 create mode 100644 go/go.mod
 create mode 100644 go/query_online.go
 create mode 100644 lua/Trans/component/init.lua
 delete mode 100644 lua/Trans/conf/init.lua
 delete mode 120000 lua/Trans/util/test/a.lua
 create mode 100644 lua/Trans/util/test/format.lua
 create mode 100644 lua/Trans/util/test/is_Chinese.lua
 create mode 100644 lua/Trans/util/test/test.lua

diff --git a/go/go.mod b/go/go.mod
new file mode 100644
index 0000000..606edce
--- /dev/null
+++ b/go/go.mod
@@ -0,0 +1,3 @@
+module query_online
+
+go 1.19
diff --git a/go/query_online.go b/go/query_online.go
new file mode 100644
index 0000000..fc5345e
--- /dev/null
+++ b/go/query_online.go
@@ -0,0 +1,50 @@
+package query_youcao
+
+import (
+	"net/url"
+	"time"
+)
+
+const (
+	youdao    = "https://openapi.youdao.com/api"
+	appKey    = "1858465a8708c121"
+	appPasswd = "fG0sitfk16nJOlIlycnLPYZn1optxUxL"
+)
+
+type data struct {
+	q        string
+	from     string
+	to       string
+	// appKey   string
+	salt     string
+	sign     string
+	signType string
+	curtime  string
+}
+
+
+func input(word string) string {
+	var input string
+	len := len(word)
+	if len > 20 {
+		input = word[:10] + string(rune(len)) + word[len-10:]
+	} else {
+		input = word
+	}
+	return input
+}
+
+func salt(_ string) string {
+	// TODO : hash salt
+	var salt string
+
+	return salt
+}
+
+func to_value(d data) url.Values {
+	// return value
+}
+
+func Query(word string) {
+
+}
diff --git a/lua/.luarc.json b/lua/.luarc.json
index 43e8c9f..97534e4 100644
--- a/lua/.luarc.json
+++ b/lua/.luarc.json
@@ -1,6 +1,7 @@
 {
     "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
     "Lua.diagnostics.disable": [
-        "unused-local"
+        "empty-block",
+        "trailing-space"
     ]
 }
\ No newline at end of file
diff --git a/lua/Trans/component/init.lua b/lua/Trans/component/init.lua
new file mode 100644
index 0000000..10247c9
--- /dev/null
+++ b/lua/Trans/component/init.lua
@@ -0,0 +1,8 @@
+local M = {}
+local order = require('Trans.conf.loader').loaded_conf.order
+
+M._ = function (query_)
+    
+end
+
+return M
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index 71d3068..19861b0 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-local display = require("Tran.conf").ui.display
+local display = require("Trans.conf.loader").loaded.conf.ui.display
 -- Example:
 -- local content = {
 --     width = 1,
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 80d8694..c182892 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -7,14 +7,6 @@ M.conf = {
             cursor = 'cursor',
             select = 'cursor'
         },
-        order = {
-            'Title',
-            'Tag',
-            'Pos',
-            'Exchange',
-            'Translation',
-            'Definition',
-        },
         window = {
             cursor = {
                 border = 'rounded',
@@ -34,8 +26,21 @@ M.conf = {
             limit = nil,
         },
     },
+    order = {
+        offline = {
+            'Title',
+            'Tag',
+            'Pos',
+            'Exchange',
+            'Translation',
+            'Definition',
+        },
+        -- online = {
+        --     -- TODO 
+        -- },
+    },
     ui = {
-        highligh = {
+        highlight = {
             TransWord = {
                 fg = '#7ee787',
                 bold = true,
@@ -79,16 +84,19 @@ M.conf = {
     base = {
         db_path = '$HOME/.vim/dict/ultimate.db',
         auto_close = true,
-        lazy_load = false,
         debug = {
             enable = true,
             type_check = true,
             unknown_conf = true,
         },
+        engine = {
+            -- TODO
+        }
     },
-    map = {
-        -- TODO
-    },
+    -- map = {
+    --     -- TODO
+    -- },
+
     -- TODO  add online translate engine
     -- online_search = {
     --     enable = false,
@@ -100,8 +108,8 @@ M.conf = {
 
 -- INFO :加载的规则 [LuaRule]
 M.replace_rules = {
-    'order',
-    'Trans.+',
+    'order.*',
+    'ui.highlight.*',
 }
 
 return M
diff --git a/lua/Trans/conf/init.lua b/lua/Trans/conf/init.lua
deleted file mode 100644
index 01baf8e..0000000
--- a/lua/Trans/conf/init.lua
+++ /dev/null
@@ -1 +0,0 @@
-return require("Trans.conf.loader").get_conf()
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
index 7ccad44..67a5e08 100644
--- a/lua/Trans/conf/loader.lua
+++ b/lua/Trans/conf/loader.lua
@@ -1,52 +1,56 @@
----@diagnostic disable: unused-local, unused-function
+-- -@diagnostic disable: unused-local, unused-function, lowercase-global
 local M = {}
 
 local replace_rules = require("Trans.conf.default").replace_rules
-local conf          = require("Trans.conf.default").conf
-local user_conf     = require("Trans").conf
-local type_check    = require("Trans.util.debug").type_check
-local is_loaded = false
 
-local function need_extend(name)
-    type_check {
-        name = { name, 'string' }
-    }
-    for _, rule in ipairs(replace_rules) do
-        if name:match(rule) then
-            return false
-        end
+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
-    return true
 end
+]]
 
--- 加载用户自定义的配置
----@param t1 table
----@param t2 table
-local function extend(t1, t2)
-    type_check {
-        t1 = { t1, 'table' },
-        t2 = { t2, 'table' },
-    }
-    for k, v in pairs(t2) do
-        if type(v) == 'table' and need_extend(k) then
-            extend(t1[k], v)
-        else
-            t1[k] = v
+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.get_conf = function()
-    if not is_loaded then
-        M.load_conf()
+
+
+M.load_conf = function(conf)
+    if #M.loaded_conf == 0 then
+        user_conf = conf or {}
+        default_conf  = require("Trans.conf.default").conf
+        pre_process()
+        M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
+        user_conf = nil
+        default_conf = nil
+    else
+        vim.notify('Configuration has been loaded...')
     end
-    return conf
 end
 
-M.load_conf = function()
-    -- loaded_conf = default_conf:extend(user_conf)
-    extend(conf, user_conf)
-    is_loaded = true
-end
+M.loaded_conf = {}
 
 return M
diff --git a/lua/Trans/conf/window.lua b/lua/Trans/conf/window.lua
index 04c6b49..1bad06c 100644
--- a/lua/Trans/conf/window.lua
+++ b/lua/Trans/conf/window.lua
@@ -1,5 +1,5 @@
 local M = {}
-local conf = require("Trans.conf").style.window
+local conf = require("Trans.conf.loader").loaded_conf.style.window
 local type_check = require("Trans.util.debug").type_check
 
 -- FIXME 
diff --git a/lua/Trans/database/init.lua b/lua/Trans/database/init.lua
index aeab460..02b1405 100644
--- a/lua/Trans/database/init.lua
+++ b/lua/Trans/database/init.lua
@@ -18,7 +18,7 @@ local query_field = {
 }
 
 -- INFO : init database
-local path = require("Trans.conf").base.db_path
+local path = require("Trans.conf.loader").loaded.conf.base.db_path
 local dict = db:open(path)
 
 -- INFO :Auto Close
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index e076815..5b4853a 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -2,12 +2,6 @@ local M = {}
 
 M.conf = {}
 
-function M.setup(conf)
-    M.conf = conf or {}
-    if conf.base and not conf.base.lazy_load then
-        require("Trans.conf.loader").load_conf()
-    end
-    -- require("Trans.setup")
-end
+M.setup = require('Trans.conf.loader').load_conf
 
 return M
diff --git a/lua/Trans/util/debug.lua b/lua/Trans/util/debug.lua
index 874954b..58cb855 100644
--- a/lua/Trans/util/debug.lua
+++ b/lua/Trans/util/debug.lua
@@ -1,7 +1,7 @@
 local M = {}
 
 -- INFO : get loaded debug conf
-local base = require("Trans").conf.base
+local base = require("Trans.conf.loader").loaded_conf.base
 local debug = require("Trans.conf.default").conf.base.debug
 if base and base.debug then
     debug = vim.tbl_extend('force', debug, base)
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index 7d9bf80..a143705 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -2,52 +2,138 @@
 local M = {}
 local type_check = require("Trans.util.debug").type_check
 
+-- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
+-- 为了解决中文字符在lua的长度和neovim显示不一致的问题
+function string:width()
+    local wid = 0
+    local bytes = { self:byte(1, #self) }
+    local index = 1
+    while true do
+        local char = bytes[index]
+        if char > 0 and char <= 127 then -- 英文[1]
+            wid = wid + 1
+            index = index + 1
+        elseif char >= 224 and char <= 239 then -- 中文[3]
+            index = index + 3 -- 原本的宽度
+            wid = wid + 2
+            -- elseif char >= 194 and char <= 223 then -- TODO :2
+            --     width = width + 2
+            --     index = index + 2
+            -- elseif char >=240 and char <= 247 then -- TODO :4
+            --     width = width + 4
+            -- index = index + 4
+        else
+            error('unknown char len:' .. tostring(char))
+        end
+
+        if index > #bytes then
+            return wid
+        end
+    end
+end
+
 -- 各种风格的基础宽度
 local style_width = {
     float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
     cursor = require("Trans.conf.window").cursor.width,
 }
 
-local m_width  = nil -- 需要被格式化窗口的高度
-local m_fields = nil -- 待格式化的字段
-local m_indent = nil -- 每行的行首缩进
-local m_length = nil -- 所有字段加起来的长度(不包括缩进和间隔)
+local s_to_b = true -- 从小到大排列
 
-local function get_rows()
-    -- TODO
-    return rows
-end
+local m_win_width -- 需要被格式化窗口的高度
+local m_fields -- 待格式化的字段
+local m_indent -- 每行的行首缩进
+local m_length -- 所有字段加起来的长度(不包括缩进和间隔)
+local m_item_width -- 每个字段的宽度
+local m_interval -- 每个字段的间隔
 
-local function do_indent(lines)
-    for i, v in ipairs(lines) do
-        lines[i] = (' '):rep(m_indent) .. v
+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 space = math.floor((m_width - m_length) / #m_fields)
+    local line = m_fields[1]
+    local space = math.floor((m_win_width - m_length) / #m_fields)
+    for i = 2, #m_fields do
+        line = line .. (' '):rep(space) .. m_fields[i]
+    end
     return line
 end
 
-local function format_to_multilines()
-    -- TODO
-    type_check {
-        interval = { interval, 'number' },
-        rows     = { rows, 'number' },
-    }
+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() -- 需要按照width排序
+    end)
 end
 
-local function get_formatted_lines()
+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 -- TODO : evaluate the width
+end
+
+local function formatted_lines()
     local lines = {}
     -- NOTE : 判断能否格式化成一行
-    if m_length + (#m_fields * m_indent) > m_width then
+    if m_length + (#m_fields * m_indent) > m_win_width then
         lines = format_to_multilines()
     else
         lines[1] = format_to_line()
     end
 
-    if m_indent then
-        do_indent(lines)
+    -- NOTE :进行缩进
+    if m_indent and m_indent > 0 then
+        for i, v in ipairs(lines) do
+            lines[i] = (' '):rep(m_indent) .. v
+        end
     end
     return lines
 end
@@ -58,9 +144,6 @@ end
 ---@param indent number 缩进的长度
 ---@return string[] lines 便于vim.api.nvim_buf_set_lines
 M.to_lines = function(style, fields, indent)
-    if not fields then
-        return {}
-    end
     type_check {
         style = { style, { 'string' } },
         fields = { fields, { 'table' } },
@@ -68,57 +151,22 @@ M.to_lines = function(style, fields, indent)
     }
 
     local length = 0
-    for _, v in ipairs(fields) do
-        length = length + #v
+    local width = 0
+    local item_size = {}
+    for i, v in ipairs(fields) do
+        width = v:width()
+        items_size[i] = width
+        length = length + width
     end
 
-    m_width      = style_width[style] - indent
-    m_indent     = indent
-    m_fields = fields
-    m_length = length
-    return get_formatted_lines()
+    m_indent     = indent or 0
+    m_win_width  = style_width[style] - m_indent
+    m_fields     = fields
+    m_length     = length
+    m_item_width = item_size
+    m_interval   = m_win_width > 50 and 6 or 4
+
+    return formatted_lines()
 end
 
--- local function get_lines(win_width, components)
---     local lines = {}
---     local interval = win_width > 40 and 6 or 4
---     local row = 1
---     local width = win_width - #components[1]
---     for i in 2, #components do
---         width = width - #components[i] - interval
---         if width < 0 then
---             width = win_width - #components[i]
---             row = row + 1
---         end
---     end
---     if row == 1 then
---         local format = '%s' .. ((' '):rep(interval) .. '%s')
---         lines[1] = string.format(format, unpack(components))
---     else
---         table.sort(components, function (a, b)
---             return #a > #b
---         end)
---         -- FIXME
---         local res, rem = #components / (row + 1), #components % (row + 1)
---         row = math.ceil(res)
---         local rol = row - rem - 1
---     end
---
---     return lines
--- end
---
--- M.format = function(style, components, indent)
---     local lines = {}
---     if #components > 1 then
---         indent = indent or 0
---         type_check {
---             style = { style, 'string' },
---             components = { components, 'table' }, ---@string[]
---             -- max_items = { max_items, { 'nil', 'number' } }, ---@string[]
---         }
---         local win_width = (style == 'float' and float_win_width or cursor_win_width) - indent
---         local res = get_lines(win_width, components)
---     end
---     return lines
--- end
 return M
diff --git a/lua/Trans/util/test/a.lua b/lua/Trans/util/test/a.lua
deleted file mode 120000
index 9b39cbe..0000000
--- a/lua/Trans/util/test/a.lua
+++ /dev/null
@@ -1 +0,0 @@
-query_youdao.lua
\ No newline at end of file
diff --git a/lua/Trans/util/test/format.lua b/lua/Trans/util/test/format.lua
new file mode 100644
index 0000000..fe66581
--- /dev/null
+++ b/lua/Trans/util/test/format.lua
@@ -0,0 +1,205 @@
+local M = {}
+-- local type_check = require("Trans.util.debug").type_check
+
+
+-- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
+-- 为了解决中文字符在lua的长度和neovim显示不一致的问题
+function string:width()
+    local width = 0
+    local bytes = { self:byte(1, #self) }
+    local index = 1
+    while true do
+        local char = bytes[index]
+        if char > 0 and char <= 127 then -- 英文[1]
+            width = width + 1
+            index = index + 1
+        elseif char >= 224 and char <= 239 then -- 中文[3]
+            index = index + 3 -- 原本的宽度
+            width = width + 2
+            -- elseif char >= 194 and char <= 223 then -- TODO :2
+            --     width = width + 2
+            --     index = index + 2
+            -- elseif char >=240 and char <= 247 then -- TODO :4
+            --     width = width + 4
+            -- index = index + 4
+        else
+            error('unknown char len:' .. tostring(char))
+        end
+        if index > #bytes then
+            return width
+        end
+    end
+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_length     -- 所有字段加起来的长度(不包括缩进和间隔)
+local m_interval   -- 每个字段的间隔
+local m_win_width  -- 需要被格式化窗口的高度
+local m_item_width -- 每个字段的宽度
+
+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]
+    local space = math.floor((m_win_width - m_length) / #m_fields)
+    for i = 2, #m_fields do
+        line = line .. (' '):rep(space) .. m_fields[i]
+    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_length + (#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_length = length
+    m_item_width = item_size
+    m_interval = m_win_width > 50 and 6 or 4
+
+    return get_formatted_lines()
+end
+
+local test = {
+    'ajlkasj',
+    'jklasjldajjnn测试',
+    'ljlklkjjlIi戳',
+    '测试将安得拉蓝色',
+    '戳将安塞',
+    'isjlkajsldj',
+}
+
+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(lines) do
+    print(v)
+end
+
+-- lines = M.to_lines('cursor', {
+--     'ajlkasj',
+--     'jklasjldajjnn测试',
+--     '测试将安得拉蓝色',
+--     'cool this',
+-- }, 4)
+
+-- for _, v in ipairs(lines) do
+--     print(v)
+-- end
+return M
+
diff --git a/lua/Trans/util/test/is_Chinese.lua b/lua/Trans/util/test/is_Chinese.lua
new file mode 100644
index 0000000..cf15825
--- /dev/null
+++ b/lua/Trans/util/test/is_Chinese.lua
@@ -0,0 +1,15 @@
+local M = {}
+-- local type_check = require("Trans.util.debug").type_check
+
+
+---@param str string
+local function is_Chinese(str)
+    for i = 1, #str do
+        if not str:byte(i) >= [[\u4e00]] then
+            return false
+        end
+    end
+    return true
+end
+
+return M
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
new file mode 100644
index 0000000..5c5d03f
--- /dev/null
+++ b/lua/Trans/util/test/test.lua
@@ -0,0 +1,13 @@
+local M = {}
+
+local a = {
+    b = 'test',
+}
+
+local c = a
+c.b = 'notest'
+
+
+
+print(a.b)
+return M

From eaf8a3acceba17576a4d8b5b7ff7fa67340238d5 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 01:59:04 +0800
Subject: [PATCH 08/17] feat: debug format function and add content function
 support

---
 lua/Trans/component/content.lua       |  96 ++++++++++++++++++++++
 lua/Trans/component/highlight.lua     |  11 +++
 lua/Trans/component/offline/Title.lua |  87 +++++++++++++++-----
 lua/Trans/component/window.lua        |  12 +++
 lua/Trans/conf/window.lua             |   2 +-
 lua/Trans/database/init.lua           |   2 +-
 lua/Trans/database/online.lua         |   0
 lua/Trans/test.lua                    |  33 ++++++++
 lua/Trans/util/base64.lua             |  39 +++++++++
 lua/Trans/util/format.lua             | 111 +++++++++++++-------------
 lua/Trans/util/test/format.lua        |  57 +++++--------
 lua/Trans/util/test/test.lua          |  17 ++--
 12 files changed, 341 insertions(+), 126 deletions(-)
 create mode 100644 lua/Trans/component/content.lua
 create mode 100644 lua/Trans/component/highlight.lua
 create mode 100644 lua/Trans/component/window.lua
 create mode 100644 lua/Trans/database/online.lua
 create mode 100644 lua/Trans/test.lua
 create mode 100644 lua/Trans/util/base64.lua

diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
new file mode 100644
index 0000000..e86572f
--- /dev/null
+++ b/lua/Trans/component/content.lua
@@ -0,0 +1,96 @@
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+M.__index = M
+M.lines = {}
+M.highlight = {}
+M.size = 0
+
+
+function M:new()
+    local content = {}
+    setmetatable(content, self)
+    return content
+end
+
+--- NOTE :highlight 格式说明:
+--- 1. 字符串
+
+
+function M:insert_items_to_line(items, opts)
+    type_check {
+        items = { items, 'table' },
+        opts = { opts, 'table', true },
+    }
+    self.size = self.size + 1 -- line数加一
+
+    local line = {
+        space = (' '):rep(opts.interval),
+        indent = opts.indent,
+        highlight = opts.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.size] = highlight
+    self.lines[self.size] = line
+end
+
+---遍历lines和高亮的迭代器
+---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:lines()
+    -- 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, l.space)
+            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 .. l.space .. l[i]
+                if hl[i] then
+                    table.insert(highlight, { name = hl[i], _start = #line - #l[i], _end = #line })
+                end
+            end
+        end
+
+        -- return line, highlights
+        lines[index] = line
+        highlights[index] = highlight
+    end
+    return lines, highlights
+end
+
+return M
diff --git a/lua/Trans/component/highlight.lua b/lua/Trans/component/highlight.lua
new file mode 100644
index 0000000..6732551
--- /dev/null
+++ b/lua/Trans/component/highlight.lua
@@ -0,0 +1,11 @@
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+M.__index = M
+
+function M:new()
+    
+end
+
+
+return M
+
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index 19861b0..4816e0e 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -1,29 +1,78 @@
 local M = {}
 
 local display = require("Trans.conf.loader").loaded.conf.ui.display
--- Example:
--- local content = {
---     width = 1,
---     height = 1;
---     lines = {
---         Highlight = {
---             'first line',
---             'second line',
---         }
---     },   ---@table
+local icon = require("Trans.conf.loader").loaded.conf.ui.icon
+
+local m_field = {}
+-- {
+--   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 function format()
---     
--- end
+local content = {
+    lines = {
+        need_format = {
+            {}, -- line
+            {}, -- line
+            {}, -- line
+            {}, -- line
+        }
+    },
+    highlight = {
+        [2] = { -- 第几行第几个组件的高亮
+            [1] = 'highlightname',
+        },
+    }
+}
 
-M.to_content = function (field)
-    -- TODO 
-    local line = ''
-    local format = '%s  %s %s %s'
-    local content = {
-        height = 1,
+local function get_items()
+    local items = {
+        m_field.word,
+    }
+    if display.phonetic then
+        table.insert(items, '[' .. m_field.phonetic .. ']')
+    end
+
+    if display.collins_star then
+        table.insert(items, icon.star:rep(m_field.collins))
+    end
+
+    if display.oxford then
+        local item
+        if m_field.oxford and m_field.oxford == 1 then
+            item = icon.isOxford
+        else
+            item = icon.notOxford
+        end
+        table.insert(items, item)
+    end
+
+    return items
+end
+
+M.content = function(field)
+    -- TODO
+    m_field = field or {}
+    local content = {}
+
+
+    content.lines = {
+        need_format = {
+            get_items()
+        },
+        highlight = {
+            [1] = { -- 第一行
+                'Trans',
+            }
+        }
     }
     return content
 end
diff --git a/lua/Trans/component/window.lua b/lua/Trans/component/window.lua
new file mode 100644
index 0000000..bb5448f
--- /dev/null
+++ b/lua/Trans/component/window.lua
@@ -0,0 +1,12 @@
+local M = {}
+local type_check = require("Trans.util.debug").type_check
+
+
+-- vim.pretty_print(vim.lsp.util._make_floating_popup_size)
+
+local v = [=[
+    local test = {{
+    }}
+]=]
+print(v)
+return M
diff --git a/lua/Trans/conf/window.lua b/lua/Trans/conf/window.lua
index 1bad06c..c81af89 100644
--- a/lua/Trans/conf/window.lua
+++ b/lua/Trans/conf/window.lua
@@ -54,7 +54,7 @@ local get_cursor_opts = function(cursor_conf)
     return opts
 end
 
-M.get_float_opts = get_float_opts(conf.float)
+M.float_opts = get_float_opts(conf.float)
 
 M.cursor_opts = get_cursor_opts(conf.cursor)
 
diff --git a/lua/Trans/database/init.lua b/lua/Trans/database/init.lua
index 02b1405..82c2a39 100644
--- a/lua/Trans/database/init.lua
+++ b/lua/Trans/database/init.lua
@@ -18,7 +18,7 @@ local query_field = {
 }
 
 -- INFO : init database
-local path = require("Trans.conf.loader").loaded.conf.base.db_path
+local path = require("Trans.conf.loader").loaded_conf.base.db_path
 local dict = db:open(path)
 
 -- INFO :Auto Close
diff --git a/lua/Trans/database/online.lua b/lua/Trans/database/online.lua
new file mode 100644
index 0000000..e69de29
diff --git a/lua/Trans/test.lua b/lua/Trans/test.lua
new file mode 100644
index 0000000..6430e03
--- /dev/null
+++ b/lua/Trans/test.lua
@@ -0,0 +1,33 @@
+local M = {}
+
+M.test = {
+    'test1',
+    'test1',
+    'test1',
+    'test1',
+}
+
+
+function M.tmp (start, stop)
+    if start > stop then
+        return
+    end
+
+    local value = M.test[start]
+    start = start + 1
+    return function ()
+
+        return start
+    end
+end
+-- function M:tmp(index)
+-- end
+
+for v in M.tmp, 1, #M.test do
+    print(v)
+end
+
+-- for i,n in square,3,0
+-- do
+--    print(i,n)
+-- end
diff --git a/lua/Trans/util/base64.lua b/lua/Trans/util/base64.lua
new file mode 100644
index 0000000..417f8e9
--- /dev/null
+++ b/lua/Trans/util/base64.lua
@@ -0,0 +1,39 @@
+local ffi = require('ffi')
+local base64 = {}
+
+local b64 = ffi.new('unsigned const char[65]',
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
+
+function base64.encode(str)
+    local band, bor, lsh, rsh = bit.band, bit.bor, bit.lshift, bit.rshift
+    local len = #str
+    local enc_len = 4 * math.ceil(len / 3) -- (len + 2) // 3 * 4 after Lua 5.3
+
+    local src = ffi.new('unsigned const char[?]', len+1, str)
+    local enc = ffi.new('unsigned char[?]', enc_len+1)
+
+    local i, j = 0, 0
+    while i < len-2 do
+        enc[j] = b64[band(rsh(src[i], 2), 0x3F)]
+        enc[j+1] = b64[bor(lsh(band(src[i], 0x3), 4), rsh(band(src[i+1], 0xF0), 4))]
+        enc[j+2] = b64[bor(lsh(band(src[i+1], 0xF), 2), rsh(band(src[i+2], 0xC0), 6))]
+        enc[j+3] = b64[band(src[i+2], 0x3F)]
+        i, j = i+3, j+4
+    end
+
+    if i < len then
+        enc[j] = b64[band(rsh(src[i], 2), 0x3F)]
+        if i == len-1 then
+            enc[j+1] = b64[lsh(band(src[i], 0x3), 4)]
+            enc[j+2] = 0x3D
+        else
+            enc[j+1] = b64[bor(lsh(band(src[i], 0x3), 4), rsh(band(src[i+1], 0xF0), 4))]
+            enc[j+2] = b64[lsh(band(src[i+1], 0xF), 2)]
+        end
+        enc[j+3] = 0x3D
+    end
+
+    return ffi.string(enc, enc_len)
+end
+
+return base64
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index a143705..9eb5ca5 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -5,52 +5,29 @@ local type_check = require("Trans.util.debug").type_check
 -- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
 -- 为了解决中文字符在lua的长度和neovim显示不一致的问题
 function string:width()
-    local wid = 0
-    local bytes = { self:byte(1, #self) }
-    local index = 1
-    while true do
-        local char = bytes[index]
-        if char > 0 and char <= 127 then -- 英文[1]
-            wid = wid + 1
-            index = index + 1
-        elseif char >= 224 and char <= 239 then -- 中文[3]
-            index = index + 3 -- 原本的宽度
-            wid = wid + 2
-            -- elseif char >= 194 and char <= 223 then -- TODO :2
-            --     width = width + 2
-            --     index = index + 2
-            -- elseif char >=240 and char <= 247 then -- TODO :4
-            --     width = width + 4
-            -- index = index + 4
-        else
-            error('unknown char len:' .. tostring(char))
-        end
-
-        if index > #bytes then
-            return wid
-        end
-    end
+    return vim.fn.strdisplaywidth(self)
 end
 
 -- 各种风格的基础宽度
 local style_width = {
-    float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
-    cursor = require("Trans.conf.window").cursor.width,
+    -- float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
+    -- cursor = require("Trans.conf.window").cursor.width,
+    cursor = 50
 }
 
 local s_to_b = true -- 从小到大排列
 
 local m_win_width -- 需要被格式化窗口的高度
 local m_fields -- 待格式化的字段
-local m_indent -- 每行的行首缩进
-local m_length -- 所有字段加起来的长度(不包括缩进和间隔)
+local m_tot_width -- 所有字段加起来的长度(不包括缩进和间隔)
 local m_item_width -- 每个字段的宽度
 local m_interval -- 每个字段的间隔
+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
+    for i = 2, m_size do
         width = width - m_item_width[i] - m_interval
         if width < 0 then
             cols = i - 1
@@ -60,14 +37,20 @@ local function caculate_format()
         end
     end
 
-    return math.ceil(#m_fields / cols), cols
+    return math.ceil(m_size / cols), cols
 end
 
 local function format_to_line()
     local line = m_fields[1]
-    local space = math.floor((m_win_width - m_length) / #m_fields)
-    for i = 2, #m_fields do
-        line = line .. (' '):rep(space) .. m_fields[i]
+    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
@@ -82,37 +65,39 @@ local function sort_tables()
     end)
 end
 
-local function format_to_multilines()
+local function format_to_multilines(rows, cols)
     local lines = {}
-    sort_tables()
 
-    --- NOTE : 计算应该格式化成多少行和列
-    local rows, cols = caculate_format()
-    local rest = #m_fields % cols
+    local rest = m_size % 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
+        lines[idx] = {}
+
         local space = (' '):rep(s_width - m_item_width[i])
-        lines[idx] = m_fields[i] .. space -- NOTE  由大到小
+        local item = m_fields[i] .. space
+
+        lines[idx][1] = item
+        lines[idx].interval = m_interval
     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]) -- 对齐空格
+            local item_idx  = index + i - 1            -- 当前操作的字段数
+            local space = (' '):rep(s_width - m_item_width[item_idx]) -- 对齐空格
+            local item = m_fields[item_idx] .. space
 
-            lines[idx] = lines[idx] .. interval .. m_fields[item] .. space -- NOTE  从大到小
+            lines[idx][j] = item -- 插入图标
         end
         index = index + stop -- 更新最宽字符的下标
     end
@@ -123,18 +108,15 @@ end
 local function formatted_lines()
     local lines = {}
     -- NOTE : 判断能否格式化成一行
-    if m_length + (#m_fields * m_indent) > m_win_width then
-        lines = format_to_multilines()
+    if m_tot_width + (m_size * m_indent) > m_win_width then
+        sort_tables()
+        --- NOTE : 计算应该格式化成多少行和列
+        local rows, cols = caculate_format()
+        lines = format_to_multilines(rows, cols)
     else
         lines[1] = format_to_line()
     end
 
-    -- NOTE :进行缩进
-    if m_indent and m_indent > 0 then
-        for i, v in ipairs(lines) do
-            lines[i] = (' '):rep(m_indent) .. v
-        end
-    end
     return lines
 end
 
@@ -155,18 +137,35 @@ M.to_lines = function(style, fields, indent)
     local item_size = {}
     for i, v in ipairs(fields) do
         width = v:width()
-        items_size[i] = 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_length     = length
+    m_size       = #m_fields
+    m_tot_width  = length
     m_item_width = item_size
     m_interval   = m_win_width > 50 and 6 or 4
 
     return formatted_lines()
 end
 
+---合并多个数组, 第一个数组将会被使用
+---@param ... string[] 需要被合并的数组
+---@return table res   合并后的数组
+M.extend_array = function(...)
+    local arrays = { ... }
+    local res = arrays[1]
+    local index = #res
+    for i = 2, #arrays do
+        for _, value in ipairs(arrays[i]) do
+            res[index] = value
+            index = index + 1
+        end
+    end
+    return res
+end
+
+
 return M
diff --git a/lua/Trans/util/test/format.lua b/lua/Trans/util/test/format.lua
index fe66581..62df1fe 100644
--- a/lua/Trans/util/test/format.lua
+++ b/lua/Trans/util/test/format.lua
@@ -5,30 +5,7 @@ local M = {}
 -- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
 -- 为了解决中文字符在lua的长度和neovim显示不一致的问题
 function string:width()
-    local width = 0
-    local bytes = { self:byte(1, #self) }
-    local index = 1
-    while true do
-        local char = bytes[index]
-        if char > 0 and char <= 127 then -- 英文[1]
-            width = width + 1
-            index = index + 1
-        elseif char >= 224 and char <= 239 then -- 中文[3]
-            index = index + 3 -- 原本的宽度
-            width = width + 2
-            -- elseif char >= 194 and char <= 223 then -- TODO :2
-            --     width = width + 2
-            --     index = index + 2
-            -- elseif char >=240 and char <= 247 then -- TODO :4
-            --     width = width + 4
-            -- index = index + 4
-        else
-            error('unknown char len:' .. tostring(char))
-        end
-        if index > #bytes then
-            return width
-        end
-    end
+    return vim.fn.strdisplaywidth(self)
 end
 
 -- 各种风格的基础宽度
@@ -40,10 +17,11 @@ local s_to_b = true -- 从小到大排列
 
 local m_fields     -- 待格式化的字段
 local m_indent     -- 每行的行首缩进
-local m_length     -- 所有字段加起来的长度(不包括缩进和间隔)
+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]
@@ -63,9 +41,15 @@ end
 
 local function format_to_line()
     local line = m_fields[1]
-    local space = math.floor((m_win_width - m_length) / #m_fields)
-    for i = 2, #m_fields do
-        line = line .. (' '):rep(space) .. m_fields[i]
+    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
@@ -124,7 +108,7 @@ end
 local function get_formatted_lines()
     local lines = {}
     -- NOTE : 判断能否格式化成一行
-    local line_size = m_length + (#m_fields * m_interval)
+    local line_size = m_tot_width + (#m_fields * m_interval)
     if line_size > m_win_width then
         lines = format_to_multilines()
     else
@@ -159,20 +143,17 @@ M.to_lines = function(style, fields, indent)
     m_indent = indent or 0
     m_win_width  = style_width[style] - m_indent
     m_fields = fields
-    m_length = length
+    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 = {
-    'ajlkasj',
-    'jklasjldajjnn测试',
-    'ljlklkjjlIi戳',
-    '测试将安得拉蓝色',
-    '戳将安塞',
-    'isjlkajsldj',
+    'isjlk测试dj',
+    '测试一下..',
 }
 
 local lines = M.to_lines('cursor', test)
@@ -187,8 +168,8 @@ local lines = M.to_lines('cursor', test)
 
 -- print('type is :' .. type(lines) .. '  size is :' .. #lines[1])
 
-for _, v in ipairs(lines) do
-    print(v)
+for _, v in ipairs(test) do
+    print(v:width())
 end
 
 -- lines = M.to_lines('cursor', {
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
index 5c5d03f..0b99fff 100644
--- a/lua/Trans/util/test/test.lua
+++ b/lua/Trans/util/test/test.lua
@@ -1,13 +1,8 @@
-local M = {}
-
-local a = {
-    b = 'test',
+local tmp = {
+    '1111',
+    '2222',
+    '3333',
+    interval = 4,
 }
 
-local c = a
-c.b = 'notest'
-
-
-
-print(a.b)
-return M
+print(table.concat(tmp, (' '):rep(tmp.interval)))

From 32cba43aa2810120cc002456e81ae54714877b48 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 15:37:58 +0800
Subject: [PATCH 09/17] feat: format code and add cmd doc

---
 lua/Trans/component/content.lua            | 28 +++++--
 lua/Trans/component/offline/Title.lua      | 90 +++++++++-----------
 lua/Trans/conf/default.lua                 |  3 +
 lua/Trans/core/READMD.md                   | 96 ++++++++++++++++++++++
 lua/Trans/core/query.lua                   |  8 +-
 lua/Trans/core/{init.lua => translate.lua} | 28 ++-----
 lua/Trans/util/format.lua                  | 61 +++++++++++---
 lua/Trans/util/test/test.lua               | 11 +--
 8 files changed, 222 insertions(+), 103 deletions(-)
 create mode 100644 lua/Trans/core/READMD.md
 rename lua/Trans/core/{init.lua => translate.lua} (94%)

diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index e86572f..66f35b7 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -12,21 +12,33 @@ function M:new()
     return content
 end
 
---- NOTE :highlight 格式说明:
---- 1. 字符串
 
 
-function M:insert_items_to_line(items, opts)
+-- 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_to_line(items)
     type_check {
         items = { items, 'table' },
-        opts = { opts, 'table', true },
     }
+
     self.size = self.size + 1 -- line数加一
 
     local line = {
-        space = (' '):rep(opts.interval),
-        indent = opts.indent,
-        highlight = opts.highlight,
+        space = (' '):rep(items.interval),
+        indent = items.indent,
+        highlight = items.highlight,
     }
     local highlight = {}
 
@@ -45,7 +57,7 @@ function M:insert_items_to_line(items, opts)
     self.lines[self.size] = line
 end
 
----遍历lines和高亮的迭代器
+
 ---Usage:
 ---     local buffer_id
 ---     local lines, highlights = M:lines()
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index 4816e0e..e8455aa 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -3,7 +3,6 @@ local M = {}
 local display = require("Trans.conf.loader").loaded.conf.ui.display
 local icon = require("Trans.conf.loader").loaded.conf.ui.icon
 
-local m_field = {}
 -- {
 --   collins = 3,
 --   definition = "n. an expression of greeting",
@@ -17,64 +16,53 @@ local m_field = {}
 -- }
 
 
-local content = {
-    lines = {
-        need_format = {
-            {}, -- line
-            {}, -- line
-            {}, -- line
-            {}, -- line
-        }
-    },
-    highlight = {
-        [2] = { -- 第几行第几个组件的高亮
-            [1] = 'highlightname',
-        },
-    }
-}
+-- local data = {
+--     { word, 'TransWord' },
+--     -- NOTE :如果平配置设置显示,并且数据库中存在则有以下字段
+--     { phonetic, 'TransPhonetic' },
+--     collins,
+--     oxford
+--     -- { phonetic, 'TransPhonetic' },
+-- }
 
-local function get_items()
-    local items = {
-        m_field.word,
+---@alias stuff
+---| 'data'       # 所有组件的信息
+---| 'highlight?' # 整个组件的高亮
+---| 'indent?'    # 每行整体的缩进
+---| 'interval?'  # 每个组件的间隔
+---@alias component stuff[]
+
+---从查询结果中获取字符串
+---@param field table 查询的结果
+---@return component component 提取的组件信息[包含多个组件]
+M.component = function(field)
+    local component = {}
+    local stuffs = {}
+    local data = {
+        {field.word, 'TransWord'},
     }
-    if display.phonetic then
-        table.insert(items, '[' .. m_field.phonetic .. ']')
+
+    if display.phonetic and field.phonetic then
+        table.insert(data, {
+            '[' .. field.phonetic .. ']', 'TransPhonetic'
+        })
     end
 
-    if display.collins_star then
-        table.insert(items, icon.star:rep(m_field.collins))
+    if display.collins and field.collins then
+        table.insert(data, {
+            icon.star:rep(field.collins)
+        })
     end
 
-    if display.oxford then
-        local item
-        if m_field.oxford and m_field.oxford == 1 then
-            item = icon.isOxford
-        else
-            item = icon.notOxford
-        end
-        table.insert(items, item)
+    if display.oxford and field.oxford then
+        table.insert(data, {
+            field.oxford
+        })
     end
 
-    return items
-end
-
-M.content = function(field)
-    -- TODO
-    m_field = field or {}
-    local content = {}
-
-
-    content.lines = {
-        need_format = {
-            get_items()
-        },
-        highlight = {
-            [1] = { -- 第一行
-                'Trans',
-            }
-        }
-    }
-    return content
+    stuffs.data = data
+    component[1] = stuffs
+    return component
 end
 
 return M
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index c182892..7cc2649 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -96,6 +96,9 @@ M.conf = {
     -- map = {
     --     -- TODO
     -- },
+    -- history = {
+    --     -- TOOD 
+    -- }
 
     -- TODO  add online translate engine
     -- online_search = {
diff --git a/lua/Trans/core/READMD.md b/lua/Trans/core/READMD.md
new file mode 100644
index 0000000..47232dd
--- /dev/null
+++ b/lua/Trans/core/READMD.md
@@ -0,0 +1,96 @@
+# 命令说明
+
+<!--toc:start-->
+- [命令说明](#命令说明)
+  - [Translate](#translate)
+  - [TranslateInput](#translateinput)
+  - [TranslateHistory](#translatehistory)
+  - [自定义](#自定义)
+    - [可选项说明](#可选项说明)
+    - [示例](#示例)
+<!--toc:end-->
+
+## Translate
+**窗口风格默认为:** `cursor`
+- 动作(action):
+    - `vsplit`         水平分屏
+    - `split`          垂直分屏
+    - `float`          窗口样式又`cursor` 变为`float`
+    - `online_query`   使用在线引擎重新进行查询
+    - `history_insert` 将此次查询的单词记录到历史记录  
+    - `next`           展示下一个引擎的查询结果(如果默认设置了多个引擎)
+    - `prev`           展示上一个查询结果
+    > 如果没有设置自动保存历史的话
+
+    - `history`        查看历史查询的记录
+
+- `online_query`:
+    - `local_add`    将此次查询的结果添加到本地数据库  
+    > **如果本地已经存在该单词,会询问是否需要覆盖掉相同的字段**
+
+    - `local_update` 和*local_add* 类似, 但是不会询问是否覆盖
+    - `diff`         对比本地查询结果和此次在线查询的区别
+
+>  **注意**: 动作是任何窗口通用的  
+## TranslateInput
+**窗口风格默认为:** `float`
+- 自行得到要查询的单词
+
+- TODO: 
+    - fuzzy match
+
+## TranslateHistory
+**窗口风格默认为:** `float`
+- 查看历史查询
+
+---
+## 自定义
+
+### 可选项说明
+- 查询方式(method): `string`
+    - `input` 自行输入需要查询的单词
+    - `last`  显示上一次查询的结果
+    - `history`
+
+- 查询引擎(engine): `string | table`
+    - `local` 本地的数据库
+    - `youcao` 有道api
+    - `baidu` 百度api
+    - `google` 谷歌api
+    - `bing` 必应api
+    - `iciba` 金山词霸api
+    - `xunfei` 讯飞api
+
+- 窗口风格(win): `string | table`
+    - 样式(style): 
+        - `cursor` 在光标附近弹出
+        - `float` 悬浮窗口
+        - `split` 在上方或者下方分屏
+        - `vsplit` 在左边或者右边分屏
+
+    - 高度(height):
+        - `value > 1` 实际高度
+        - `0 <= value <= 1` 相对高度
+        - `0 < value` 无限制
+
+    - 宽度(width):
+        > 和`高度(height)`相同
+### 示例
+```lua
+vim.keymap.set('n', 'mi', function ()
+    require('Trans').translate({
+        method = 'input',
+        engine = { -- 异步查询所有的引擎, 按照列表
+            'local',
+            'youdao',
+            'baidu'
+        },
+        -- view = 'cursor'
+        view = {
+            style = 'cursor',
+            height = 50,
+            width = 30,
+        }
+    })
+end, { desc = '在光标旁弹出输入的单词释义'})
+```
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
index 2f3f43e..e8f8a49 100644
--- a/lua/Trans/core/query.lua
+++ b/lua/Trans/core/query.lua
@@ -14,24 +14,24 @@ local function get_select()
     return word
 end
 
+
 M.get_query_res = function(method)
     type_check {
         method = { method, 'string' },
     }
-
-    -- NOTE : get query word
     local word = ''
     if method == 'cursor' then
         word = vim.fn.expand('<cword>')
     elseif method == 'select' then
-        word = get_select():match('%s+')
+        word = get_select():match('%S+')
     elseif method == 'input' then
         word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
     else
         error('unknown method')
     end
-    -- FIXME
+
     return query(word)
 end
 
+
 return M
diff --git a/lua/Trans/core/init.lua b/lua/Trans/core/translate.lua
similarity index 94%
rename from lua/Trans/core/init.lua
rename to lua/Trans/core/translate.lua
index 6e28f2d..fb8cd0e 100644
--- a/lua/Trans/core/init.lua
+++ b/lua/Trans/core/translate.lua
@@ -1,32 +1,20 @@
 local M          = {}
-local api        = vim.api
-local conf       = require("Trans").conf
-local display    = conf.display
-local icon       = conf.icon
-local order      = conf.order
-local auto_close = conf.auto_close
-local view       = conf.view
 
 
-local highlight = {
-    word     = 'TransWord',
-    phonetic = 'TransPhonetic',
-    ref      = 'TransRef',
-    tag      = 'TransTag',
-    exchange = 'TransExchange',
-    pos      = 'TransPos',
-    zh       = 'TransZh',
-    en       = 'TransEn',
+local opt = {
+    method = 'select',
+    view = 'cursor',
 }
 
-
-
-
-M.TransLate = function(opts)
+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
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index 9eb5ca5..5f892d2 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -10,9 +10,9 @@ end
 
 -- 各种风格的基础宽度
 local style_width = {
-    -- float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
-    -- cursor = require("Trans.conf.window").cursor.width,
-    cursor = 50
+    float = require("Trans.conf.window").float.width, -- NOTE : need window parsed conf
+    cursor = require("Trans.conf.window").cursor.width,
+    -- cursor = 50
 }
 
 local s_to_b = true -- 从小到大排列
@@ -92,10 +92,10 @@ local function format_to_multilines(rows, cols)
         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_idx  = index + i - 1            -- 当前操作的字段数
-            local space = (' '):rep(s_width - m_item_width[item_idx]) -- 对齐空格
-            local item = m_fields[item_idx] .. space
+            local idx      = s_to_b and stop - i + 1 or i -- 当前操作的行数
+            local item_idx = index + i - 1 -- 当前操作的字段数
+            local space    = (' '):rep(s_width - m_item_width[item_idx]) -- 对齐空格
+            local item     = m_fields[item_idx] .. space
 
             lines[idx][j] = item -- 插入图标
         end
@@ -120,16 +120,46 @@ local function formatted_lines()
     return lines
 end
 
+-- EXAMPLE : 接受的形式
+-- local content = {
+--     { word, 'TransWord' },
+--     { phonetic, 'TransPhonetic' },
+--     collins,
+--     oxford
+--     -- { phonetic, 'TransPhonetic' },
+--  NOTE :
+-- 可选的:
+-- 1. highlight 整个content的高亮
+-- 2. indent    缩进
+-- 2. space     各个组件的及间隔
+-- }
+
+
+-- EXAMPLE : 返回的形式
+local lines = {
+    { items, opts },
+    { items, opts },
+    { items, opts },
+    -- items: string[]
+    -- opts {
+    --     highlight
+    --     indent
+    -- }
+}
+
+local function format_stuff(stuff)
+
+end
+
+---@alias formatted_items table
 ---将组件格式化成相应的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)
+---@param component table 需要格式化的字段
+---@return formatted_items[] lines
+M.format = function(style, component)
     type_check {
         style = { style, { 'string' } },
-        fields = { fields, { 'table' } },
-        indent = { indent, { 'number' }, true },
+        component = { component, { 'table' } },
     }
 
     local length = 0
@@ -151,6 +181,11 @@ M.to_lines = function(style, fields, indent)
     return formatted_lines()
 end
 
+
+
+
+
+
 ---合并多个数组, 第一个数组将会被使用
 ---@param ... string[] 需要被合并的数组
 ---@return table res   合并后的数组
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
index 0b99fff..fa4d1e9 100644
--- a/lua/Trans/util/test/test.lua
+++ b/lua/Trans/util/test/test.lua
@@ -1,8 +1,5 @@
-local tmp = {
-    '1111',
-    '2222',
-    '3333',
-    interval = 4,
-}
+local a = nil
 
-print(table.concat(tmp, (' '):rep(tmp.interval)))
+
+
+print((' '):rep(a))

From fef956e36df8b98c3ff485db4253d282f7e2b363 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 18:57:20 +0800
Subject: [PATCH 10/17] feat: add some bugs

---
 lua/.luarc.json                               |  5 ++
 lua/Trans/api/READMD.md                       |  7 +++
 lua/Trans/api/init.lua                        |  8 +++
 .../{database/init.lua => api/query.lua}      | 27 +++++-----
 lua/Trans/conf/default.lua                    |  3 +-
 lua/Trans/conf/loader.lua                     | 21 +++-----
 lua/Trans/core/READMD.md                      |  6 +--
 lua/Trans/core/query.lua                      | 22 +++++++-
 lua/Trans/database/online.lua                 |  0
 lua/Trans/init.lua                            |  6 ++-
 lua/Trans/test.lua                            | 33 ------------
 lua/Trans/wrapper/translate.lua               | 52 +++++++++++++++++++
 12 files changed, 125 insertions(+), 65 deletions(-)
 create mode 100644 lua/Trans/api/READMD.md
 create mode 100644 lua/Trans/api/init.lua
 rename lua/Trans/{database/init.lua => api/query.lua} (97%)
 delete mode 100644 lua/Trans/database/online.lua
 delete mode 100644 lua/Trans/test.lua
 create mode 100644 lua/Trans/wrapper/translate.lua

diff --git a/lua/.luarc.json b/lua/.luarc.json
index 97534e4..cb3ed2f 100644
--- a/lua/.luarc.json
+++ b/lua/.luarc.json
@@ -3,5 +3,10 @@
     "Lua.diagnostics.disable": [
         "empty-block",
         "trailing-space"
+    ],
+    "Lua.diagnostics.globals": [
+        "vim",
+        "user_conf",
+        "default_conf"
     ]
 }
\ No newline at end of file
diff --git a/lua/Trans/api/READMD.md b/lua/Trans/api/READMD.md
new file mode 100644
index 0000000..bdc0653
--- /dev/null
+++ b/lua/Trans/api/READMD.md
@@ -0,0 +1,7 @@
+# API说明
+
+## 概述
+- 翻译查询
+    - ``
+- 字段处理
+- 窗口显示
diff --git a/lua/Trans/api/init.lua b/lua/Trans/api/init.lua
new file mode 100644
index 0000000..6efad78
--- /dev/null
+++ b/lua/Trans/api/init.lua
@@ -0,0 +1,8 @@
+local M = {}
+
+local query_warpper = require 'Trans.api.query'
+
+M.query = query_warpper.query
+
+
+return M
diff --git a/lua/Trans/database/init.lua b/lua/Trans/api/query.lua
similarity index 97%
rename from lua/Trans/database/init.lua
rename to lua/Trans/api/query.lua
index 82c2a39..65ee90f 100644
--- a/lua/Trans/database/init.lua
+++ b/lua/Trans/api/query.lua
@@ -5,18 +5,6 @@ if not _ then
 end
 local type_check = require("Trans.util.debug").type_check
 
-local query_field = {
-    'word',
-    'phonetic',
-    'definition',
-    'translation',
-    'pos',
-    'collins',
-    'oxford',
-    'tag',
-    'exchange',
-}
-
 -- INFO : init database
 local path = require("Trans.conf.loader").loaded_conf.base.db_path
 local dict = db:open(path)
@@ -31,6 +19,20 @@ vim.api.nvim_create_autocmd('VimLeavePre', {
     end
 })
 
+
+local query_field = {
+    'word',
+    'phonetic',
+    'definition',
+    'translation',
+    'pos',
+    'collins',
+    'oxford',
+    'tag',
+    'exchange',
+}
+
+-- NOTE : local query
 M.query = function(arg)
     -- TODO : more opts
     type_check {
@@ -45,4 +47,5 @@ M.query = function(arg)
     return res[1]
 end
 
+
 return M
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 7cc2649..2677f0b 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -4,7 +4,7 @@ M.conf = {
     style = {
         ui = {
             input = 'float',
-            cursor = 'cursor',
+            normal = 'cursor',
             select = 'cursor'
         },
         window = {
@@ -115,4 +115,5 @@ M.replace_rules = {
     'ui.highlight.*',
 }
 
+
 return M
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
index 67a5e08..90f0803 100644
--- a/lua/Trans/conf/loader.lua
+++ b/lua/Trans/conf/loader.lua
@@ -13,6 +13,7 @@ if def and usr then
 end
 ]]
 
+
 local plain_format = [[
 default_conf.%s = user_conf.%s or default_conf.%s
 ]]
@@ -36,21 +37,15 @@ local function pre_process()
     end
 end
 
-
-
 M.load_conf = function(conf)
-    if #M.loaded_conf == 0 then
-        user_conf = conf or {}
-        default_conf  = require("Trans.conf.default").conf
-        pre_process()
-        M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
-        user_conf = nil
-        default_conf = nil
-    else
-        vim.notify('Configuration has been loaded...')
-    end
+    user_conf    = conf or {}
+    default_conf = require("Trans.conf.default").conf
+    pre_process()
+    M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
+    user_conf = nil
+    default_conf = nil
 end
 
-M.loaded_conf = {}
+M.loaded_conf = nil
 
 return M
diff --git a/lua/Trans/core/READMD.md b/lua/Trans/core/READMD.md
index 47232dd..e86391d 100644
--- a/lua/Trans/core/READMD.md
+++ b/lua/Trans/core/READMD.md
@@ -79,14 +79,14 @@
 ```lua
 vim.keymap.set('n', 'mi', function ()
     require('Trans').translate({
-        method = 'input',
+        method = 'input', -- 不填则自动判断mode获取查询的单词
         engine = { -- 异步查询所有的引擎, 按照列表
             'local',
             'youdao',
             'baidu'
         },
-        -- view = 'cursor'
-        view = {
+        -- win = 'cursor'
+        win = {
             style = 'cursor',
             height = 50,
             width = 30,
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
index e8f8a49..ed53437 100644
--- a/lua/Trans/core/query.lua
+++ b/lua/Trans/core/query.lua
@@ -15,6 +15,27 @@ local function get_select()
 end
 
 
+local function get_word(method)
+    if not method then
+        local mode = vim.api.nvim_get_mode()
+        if mode == 'n' then
+            return vim.fn.expand('<cword>')
+        elseif mode == 'v' then
+            return get_select()
+        else
+            error('invalid mode')
+        end
+    end
+
+    if method == 'input' then
+        return vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
+
+    -- TODO : other method
+    else
+        error('invalid method')
+    end
+end
+
 M.get_query_res = function(method)
     type_check {
         method = { method, 'string' },
@@ -25,7 +46,6 @@ M.get_query_res = function(method)
     elseif method == 'select' then
         word = get_select():match('%S+')
     elseif method == 'input' then
-        word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
     else
         error('unknown method')
     end
diff --git a/lua/Trans/database/online.lua b/lua/Trans/database/online.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 5b4853a..5090cb7 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -1,7 +1,9 @@
 local M = {}
 
-M.conf = {}
-
 M.setup = require('Trans.conf.loader').load_conf
 
+M.translate = require('Tran.wrapper.translate')
+
+
+
 return M
diff --git a/lua/Trans/test.lua b/lua/Trans/test.lua
deleted file mode 100644
index 6430e03..0000000
--- a/lua/Trans/test.lua
+++ /dev/null
@@ -1,33 +0,0 @@
-local M = {}
-
-M.test = {
-    'test1',
-    'test1',
-    'test1',
-    'test1',
-}
-
-
-function M.tmp (start, stop)
-    if start > stop then
-        return
-    end
-
-    local value = M.test[start]
-    start = start + 1
-    return function ()
-
-        return start
-    end
-end
--- function M:tmp(index)
--- end
-
-for v in M.tmp, 1, #M.test do
-    print(v)
-end
-
--- for i,n in square,3,0
--- do
---    print(i,n)
--- end
diff --git a/lua/Trans/wrapper/translate.lua b/lua/Trans/wrapper/translate.lua
new file mode 100644
index 0000000..e1e9a8b
--- /dev/null
+++ b/lua/Trans/wrapper/translate.lua
@@ -0,0 +1,52 @@
+local type_check = require("Trans.util.debug").type_check
+
+local window = require("Trans.conf.window")
+-- Default conf
+local core = require("Trasn.core")
+
+local function get_opts(opts)
+    local default_conf = {
+        method = vim.api.nvim_get_mode(),
+        engine = {
+            'local',
+            -- TODO : other engine
+        },
+        win = window.cursor_win,
+    }
+
+    -- TODO :process win height and width
+    if type(opts.engine) == 'string' then
+        opts.engine = { opts.engine }
+    end
+
+    if opts.win then
+        opts.win = window.process(opts.win)
+    end
+    return vim.tbl_extend('force', default_conf, opts)
+end
+
+local function translate(opts)
+    type_check {
+        opts = { opts, 'table' }
+    }
+    opts = get_opts(opts or {})
+
+
+    local field = core.query(opts)
+
+    opts = {
+        field = field,
+    }
+
+    local content = core.process(opts)
+
+    opts = {
+        style = opts.style,
+        height = opts.height,
+        width = opts.width,
+        content = content,
+    }
+    core.show(opts)
+end
+
+return translate

From 67c6ffa989d0de489f8192ccfbe9b8ee9c1071d5 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 21:30:16 +0800
Subject: [PATCH 11/17] feat: add more bugs

---
 README.md                               |  2 +-
 lua/Trans/api/{READMD.md => README.md}  |  0
 lua/Trans/component/content.lua         | 12 +++---
 lua/Trans/component/init.lua            |  8 ----
 lua/Trans/component/window.lua          | 12 ------
 lua/Trans/conf/base.lua                 |  9 +----
 lua/Trans/conf/default.lua              |  5 ++-
 lua/Trans/conf/loader.lua               | 14 +++++++
 lua/Trans/core/{READMD.md => README.md} |  4 +-
 lua/Trans/core/content.lua              | 19 ---------
 lua/Trans/core/init.lua                 |  7 ++++
 lua/Trans/core/process.lua              | 22 ++++++++++
 lua/Trans/core/show_win.lua             | 53 +++++++++++++++++++++++++
 lua/Trans/init.lua                      |  4 +-
 lua/Trans/ui/init.lua                   |  0
 lua/Trans/util/format.lua               | 32 +++++----------
 lua/Trans/window/content.lua            | 18 ---------
 lua/Trans/window/display.lua            | 29 --------------
 lua/Trans/window/init.lua               |  0
 lua/Trans/wrapper/translate.lua         | 43 +++++++++++++-------
 20 files changed, 149 insertions(+), 144 deletions(-)
 rename lua/Trans/api/{READMD.md => README.md} (100%)
 delete mode 100644 lua/Trans/component/init.lua
 delete mode 100644 lua/Trans/component/window.lua
 rename lua/Trans/core/{READMD.md => README.md} (97%)
 delete mode 100644 lua/Trans/core/content.lua
 create mode 100644 lua/Trans/core/init.lua
 create mode 100644 lua/Trans/core/process.lua
 create mode 100644 lua/Trans/core/show_win.lua
 delete mode 100644 lua/Trans/ui/init.lua
 delete mode 100644 lua/Trans/window/content.lua
 delete mode 100644 lua/Trans/window/display.lua
 delete mode 100644 lua/Trans/window/init.lua

diff --git a/README.md b/README.md
index dbd6ee5..f294f75 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@
 - 支持 `normal`和 `visual`模式
 > 不支持 visual-block mode
   
-- 词库单词量: `43w`
+- 本地词库单词量: `430w`
   
 ## 屏幕截图
 ![ScreenShot](./screenshot.gif)
diff --git a/lua/Trans/api/READMD.md b/lua/Trans/api/README.md
similarity index 100%
rename from lua/Trans/api/READMD.md
rename to lua/Trans/api/README.md
diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 66f35b7..7102f78 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -12,14 +12,12 @@ function M:new()
     return content
 end
 
-
-
 -- NOTE :
 -- local items = {
 --     -- style1: string 不需要单独设置高亮的情况
---     'text', 
+--     'text',
 --     -- style2: string[] 需要设置高亮,第二个名称为高亮组
---     {'text2', 'highlight name'}, 
+--     {'text2', 'highlight name'},
 -- }
 
 -- local opts = {
@@ -28,7 +26,7 @@ end
 --     indent = 4 -- integer 该行的应该在开头的缩进
 --     interval = 4 -- integer 该行组件的间隔
 -- }
-function M:insert_items_to_line(items)
+function M:insert(items)
     type_check {
         items = { items, 'table' },
     }
@@ -57,7 +55,6 @@ function M:insert_items_to_line(items)
     self.lines[self.size] = line
 end
 
-
 ---Usage:
 ---     local buffer_id
 ---     local lines, highlights = M:lines()
@@ -93,7 +90,8 @@ function M:lines()
             for i = 2, #l do
                 line = line .. l.space .. l[i]
                 if hl[i] then
-                    table.insert(highlight, { name = hl[i], _start = #line - #l[i], _end = #line })
+                    local _end = #line
+                    table.insert(highlight, { name = hl[i], _start = _end - #l[i], _end = _end })
                 end
             end
         end
diff --git a/lua/Trans/component/init.lua b/lua/Trans/component/init.lua
deleted file mode 100644
index 10247c9..0000000
--- a/lua/Trans/component/init.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-local M = {}
-local order = require('Trans.conf.loader').loaded_conf.order
-
-M._ = function (query_)
-    
-end
-
-return M
diff --git a/lua/Trans/component/window.lua b/lua/Trans/component/window.lua
deleted file mode 100644
index bb5448f..0000000
--- a/lua/Trans/component/window.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local M = {}
-local type_check = require("Trans.util.debug").type_check
-
-
--- vim.pretty_print(vim.lsp.util._make_floating_popup_size)
-
-local v = [=[
-    local test = {{
-    }}
-]=]
-print(v)
-return M
diff --git a/lua/Trans/conf/base.lua b/lua/Trans/conf/base.lua
index 42c4d8e..c247c60 100644
--- a/lua/Trans/conf/base.lua
+++ b/lua/Trans/conf/base.lua
@@ -1,17 +1,12 @@
 local M = {}
-
+ 
 local buf_opts = {
-    filetype = 'Trans'
 }
 
 local buf = vim.api.nvim_create_buf(false, true)
-for k, v in pairs(buf_opts) do
-    vim.api.nvim_buf_set_option(buf, k, v)
-end
 
 M.buf = buf
 
-M.group = vim.api.nvim_create_augroup('Trans', { clear = true })
-
+M.augroup = vim.api.nvim_create_augroup('Trans', { clear = true })
 
 return M
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 2677f0b..845e0cc 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -15,8 +15,8 @@ M.conf = {
             },
             float = {
                 border = 'rounded',
-                width = 0.8,
-                height = 0.9,
+                width = 0.9,
+                height = 0.8,
             },
             -- NOTE :如果你想限制某个组件的行数,可以设置 (名称与order相同)
             -- Example:
@@ -91,6 +91,7 @@ M.conf = {
         },
         engine = {
             -- TODO
+            'local',
         }
     },
     -- map = {
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
index 90f0803..ef8f53f 100644
--- a/lua/Trans/conf/loader.lua
+++ b/lua/Trans/conf/loader.lua
@@ -40,8 +40,22 @@ 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 width = M.loaded_conf.style.window.cursor.float.width
+    local height = M.loaded_conf.style.window.cursor.float.height
+
+    if width > 0 and width <= 1 then
+        M.loaded_conf.style.window.cursor.float.width = math.floor(width * vim.o.columns)
+    end
+
+    if height > 0 and height <= 1 then
+        M.loaded_conf.style.window.cursor.float.height = math.floor(height * (vim.o.lines - vim.o.cmdheight))
+    end
+
     user_conf = nil
     default_conf = nil
 end
diff --git a/lua/Trans/core/READMD.md b/lua/Trans/core/README.md
similarity index 97%
rename from lua/Trans/core/READMD.md
rename to lua/Trans/core/README.md
index e86391d..5fa3070 100644
--- a/lua/Trans/core/READMD.md
+++ b/lua/Trans/core/README.md
@@ -53,7 +53,7 @@
     - `history`
 
 - 查询引擎(engine): `string | table`
-    - `local` 本地的数据库
+    - `offline` 离线的数据库
     - `youcao` 有道api
     - `baidu` 百度api
     - `google` 谷歌api
@@ -81,7 +81,7 @@ vim.keymap.set('n', 'mi', function ()
     require('Trans').translate({
         method = 'input', -- 不填则自动判断mode获取查询的单词
         engine = { -- 异步查询所有的引擎, 按照列表
-            'local',
+            'offline',
             'youdao',
             'baidu'
         },
diff --git a/lua/Trans/core/content.lua b/lua/Trans/core/content.lua
deleted file mode 100644
index 0cc6206..0000000
--- a/lua/Trans/core/content.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-local M = {}
-local type_check = require("Trans.util.debug").type_check
-
-local offline_dir = debug.getinfo(1, "S").source:sub(2):match('.*Trans') .. '/component/offline'
-
-M.to_content = function(query_res)
-    type_check {
-        query_res = { query_res, 'table' }
-    }
-    local content = {}
-    for file in vim.fs.dir(offline_dir) do
-        local res = require("Trans.component.offline." .. file:gsub('.lua', '')).to_content(query_res)
-        assert(res)
-        table.insert(content, res)
-    end
-    return content
-end
-
-return M
diff --git a/lua/Trans/core/init.lua b/lua/Trans/core/init.lua
new file mode 100644
index 0000000..fd633ca
--- /dev/null
+++ b/lua/Trans/core/init.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.process = require('Trans.core.process')
+M.query = require('Trans.core.query')
+M.show_win = require('Trans.core.show_win')
+
+return M
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
new file mode 100644
index 0000000..f5ff007
--- /dev/null
+++ b/lua/Trans/core/process.lua
@@ -0,0 +1,22 @@
+local type_check = require("Trans.util.debug").type_check
+local format = require("Trans.util.format")
+
+
+-- NOTE : 将请求得到的字段进行处理
+-- local offline_dir = debug.getinfo(1, "S").source:sub(2):match('.*Trans') .. '/component/offline'
+local function process (opts)
+    type_check {
+        opts = { opts, 'table' }
+    }
+    local content = require('Trans.component.content'):new()
+
+    for _, v in ipairs(opts.order) do
+        local component = format.format(opts.win_style, require("Trans.component" .. opts.engine .. v))
+        content:insert(component)
+    end
+
+    return content:lines()
+end
+
+
+return process
diff --git a/lua/Trans/core/show_win.lua b/lua/Trans/core/show_win.lua
new file mode 100644
index 0000000..7c17fa3
--- /dev/null
+++ b/lua/Trans/core/show_win.lua
@@ -0,0 +1,53 @@
+local type_check = require("Trans.util.debug").type_check
+
+local buf_opts = {
+    filetype = 'Trans',
+    modifiable = false,
+}
+
+-- local win_opts = {
+--     winhl = 'Normal:TransWinNormal, FloatBorder:TransWinBorder'
+-- }
+
+local function caculate_format(height, width)
+    local col = math.floor((vim.o.lines - height - vim.o.cmdheight) / 2)
+    local row = math.floor((vim.o.columns - width) / 2)
+    return row, col
+end
+
+local function show_win(opts)
+    type_check {
+        opts = { opts, 'table' },
+        win = { opts.win, 'table' },
+        highlight = { opts.highlight, 'table', true },
+    }
+
+    local bufnr = vim.api.nvim_create_buf(false, true)
+    for k, v in pairs(buf_opts) do
+        vim.api.nvim_buf_set_option(bufnr, k, v)
+    end
+
+    local is_float = opts.style == 'float'
+    local win_opts = {
+        relative = opts.style == 'float' and 'editor' or 'cursor',
+        width = opts.width,
+        height = opts.height,
+        style = 'minimal',
+        border = 'rounded',
+        title = 'Trans',
+        title_pos = 'center',
+        focusable = true,
+        zindex = 100,
+    }
+    if is_float then
+        win_opts.row, win_opts.col = caculate_format(win_opts.height, win_opts.width)
+    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
+
+return show_win
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 5090cb7..380e4fb 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -2,8 +2,6 @@ local M = {}
 
 M.setup = require('Trans.conf.loader').load_conf
 
-M.translate = require('Tran.wrapper.translate')
-
-
+M.translate = require('Tran.core.translate')
 
 return M
diff --git a/lua/Trans/ui/init.lua b/lua/Trans/ui/init.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index 5f892d2..e3c520d 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -1,4 +1,3 @@
----@diagnostic disable: undefined-global
 local M = {}
 local type_check = require("Trans.util.debug").type_check
 
@@ -8,12 +7,6 @@ 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 = require("Trans.conf.window").cursor.width,
-    -- cursor = 50
-}
 
 local s_to_b = true -- 从小到大排列
 
@@ -136,20 +129,17 @@ end
 
 
 -- EXAMPLE : 返回的形式
-local lines = {
-    { items, opts },
-    { items, opts },
-    { items, opts },
-    -- items: string[]
-    -- opts {
-    --     highlight
-    --     indent
-    -- }
-}
+-- local lines = {
+--     { items, opts },
+--     { items, opts },
+--     { items, opts },
+--     -- items: string[]
+--     -- opts {
+--     --     highlight
+--     --     indent
+--     -- }
+-- }
 
-local function format_stuff(stuff)
-
-end
 
 ---@alias formatted_items table
 ---将组件格式化成相应的vim支持的lines格式
@@ -184,8 +174,6 @@ end
 
 
 
-
-
 ---合并多个数组, 第一个数组将会被使用
 ---@param ... string[] 需要被合并的数组
 ---@return table res   合并后的数组
diff --git a/lua/Trans/window/content.lua b/lua/Trans/window/content.lua
deleted file mode 100644
index 1b86632..0000000
--- a/lua/Trans/window/content.lua
+++ /dev/null
@@ -1,18 +0,0 @@
-local M = {}
-
---[[
-content = {
-    lines = {}          ---@type string[]
-    highlight = {}
-}
---]]
----@param contents string[]
-M.set = function (win, contents)
-    vim.validate {
-        contents = { contents, 'table' },
-    }
-    -- TODO 
-end
-
-
-return M
diff --git a/lua/Trans/window/display.lua b/lua/Trans/window/display.lua
deleted file mode 100644
index 567149b..0000000
--- a/lua/Trans/window/display.lua
+++ /dev/null
@@ -1,29 +0,0 @@
-local M = {}
-local api = vim.api
-local util = require("Trans.window.util")
-M.buf = util.init_buf()
-
---- 浮动窗口的风格
----@param conf table 自定义配置
-M.show_float_win = function(conf)
-    vim.validate {
-        conf = { conf, 'table' },
-    }
-    local opts = util.get_float_opts(conf)
-    local win = api.nvim_open_win(M.buf, true, opts)
-    return win
-end
-
-M.show_cursor_win = function(conf)
-    vim.validate {
-        conf = { conf, 'table' },
-    }
-    local opts = util.get_cursor_opts(conf)
-    local win = api.nvim_open_win(M.buf, true, opts)
-    return win
-end
-
--- TODO <++> more window style
-
-
-return M
diff --git a/lua/Trans/window/init.lua b/lua/Trans/window/init.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/lua/Trans/wrapper/translate.lua b/lua/Trans/wrapper/translate.lua
index e1e9a8b..4cbffd3 100644
--- a/lua/Trans/wrapper/translate.lua
+++ b/lua/Trans/wrapper/translate.lua
@@ -1,9 +1,9 @@
 local type_check = require("Trans.util.debug").type_check
-
-local window = require("Trans.conf.window")
 -- Default conf
+local conf = require("Trans.conf.loader").loaded_conf
 local core = require("Trasn.core")
 
+
 local function get_opts(opts)
     local default_conf = {
         method = vim.api.nvim_get_mode(),
@@ -11,17 +11,28 @@ local function get_opts(opts)
             'local',
             -- TODO : other engine
         },
-        win = window.cursor_win,
+        win = {
+            style = 'cursor',
+            width = conf.window.cursor.width,
+            height = conf.window.cursor.height
+        },
     }
 
-    -- TODO :process win height and width
     if type(opts.engine) == 'string' then
         opts.engine = { opts.engine }
     end
 
     if opts.win then
-        opts.win = window.process(opts.win)
+        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
 
@@ -29,24 +40,28 @@ local function translate(opts)
     type_check {
         opts = { opts, 'table' }
     }
+
+    --- TODO : 异步请求
+    -- NOTE : 这里只处理了本地的请求
     opts = get_opts(opts or {})
-
-
     local field = core.query(opts)
 
-    opts = {
+    local proc_opts = {
         field = field,
+        order = conf.order['offline'],
+        engine = 'offline',
+        win_style = opts.win.style,
     }
 
-    local content = core.process(opts)
+    local content, highlight = core.process(proc_opts)
 
-    opts = {
-        style = opts.style,
-        height = opts.height,
-        width = opts.width,
+    local win_opts = {
+        win = opts.win,
         content = content,
+        highlight = highlight,
     }
-    core.show(opts)
+
+    core.show_win(win_opts)
 end
 
 return translate

From ff36cfd549d30f2ab38a29e19518432dbe9086b7 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 23:20:56 +0800
Subject: [PATCH 12/17] feat: add more bugs

---
 lua/Trans/api/query.lua               |   3 +-
 lua/Trans/component/content.lua       |   2 +-
 lua/Trans/component/offline/Title.lua |   4 +-
 lua/Trans/conf/base.lua               |  12 -
 lua/Trans/conf/default.lua            |  19 +-
 lua/Trans/conf/loader.lua             |   8 +-
 lua/Trans/core/backup.lua             | 294 +++++++++++++++++++
 lua/Trans/core/process.lua            |  28 +-
 lua/Trans/core/query.lua              |  51 ++--
 lua/Trans/core/show_win.lua           |  23 +-
 lua/Trans/core/translate.lua          | 390 +++++++-------------------
 lua/Trans/init.lua                    |   9 +-
 lua/Trans/setup.lua                   |  27 +-
 lua/Trans/util/debug.lua              |   9 +-
 lua/Trans/util/format.lua             |   9 +-
 lua/Trans/util/test/test.lua          |   7 +-
 lua/Trans/wrapper/translate.lua       |  67 -----
 17 files changed, 497 insertions(+), 465 deletions(-)
 delete mode 100644 lua/Trans/conf/base.lua
 create mode 100644 lua/Trans/core/backup.lua
 delete mode 100644 lua/Trans/wrapper/translate.lua

diff --git a/lua/Trans/api/query.lua b/lua/Trans/api/query.lua
index 65ee90f..d2645af 100644
--- a/lua/Trans/api/query.lua
+++ b/lua/Trans/api/query.lua
@@ -11,7 +11,7 @@ local dict = db:open(path)
 
 -- INFO :Auto Close
 vim.api.nvim_create_autocmd('VimLeavePre', {
-    group = require("Trans.conf.base").autogroup,
+    group = require("Trans").augroup,
     callback = function()
         if db:isopen() then
             db:close()
@@ -19,7 +19,6 @@ vim.api.nvim_create_autocmd('VimLeavePre', {
     end
 })
 
-
 local query_field = {
     'word',
     'phonetic',
diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 7102f78..3c6f907 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -64,7 +64,7 @@ end
 ---     end
 ---@return table line
 ---@return table highlight
-function M:lines()
+function M:data()
     -- NOTE 返回格式化的行,如果需要高亮,则第二个参数返回高亮
     local lines = {}
     local highlights = {}
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index e8455aa..d02eb69 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -1,7 +1,7 @@
 local M = {}
 
-local display = require("Trans.conf.loader").loaded.conf.ui.display
-local icon = require("Trans.conf.loader").loaded.conf.ui.icon
+local display = require("Trans.conf.loader").loaded_conf.ui.display
+local icon = require("Trans.conf.loader").loaded_conf.ui.icon
 
 -- {
 --   collins = 3,
diff --git a/lua/Trans/conf/base.lua b/lua/Trans/conf/base.lua
deleted file mode 100644
index c247c60..0000000
--- a/lua/Trans/conf/base.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local M = {}
- 
-local buf_opts = {
-}
-
-local buf = vim.api.nvim_create_buf(false, true)
-
-M.buf = buf
-
-M.augroup = vim.api.nvim_create_augroup('Trans', { clear = true })
-
-return M
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 845e0cc..5e92c18 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -29,11 +29,11 @@ M.conf = {
     order = {
         offline = {
             'Title',
-            'Tag',
-            'Pos',
-            'Exchange',
-            'Translation',
-            'Definition',
+            -- 'Tag',
+            -- 'Pos',
+            -- 'Exchange',
+            -- 'Translation',
+            -- 'Definition',
         },
         -- online = {
         --     -- TODO 
@@ -61,10 +61,10 @@ M.conf = {
             TransPos = {
                 link = 'TransTag',
             },
-            TransZh = {
+            TransTranslation = {
                 link = 'TransWord',
             },
-            TransEn = {
+            TransDefinition = {
                 fg = '#bc8cff',
             },
         },
@@ -84,11 +84,6 @@ M.conf = {
     base = {
         db_path = '$HOME/.vim/dict/ultimate.db',
         auto_close = true,
-        debug = {
-            enable = true,
-            type_check = true,
-            unknown_conf = true,
-        },
         engine = {
             -- TODO
             'local',
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
index ef8f53f..3b3684f 100644
--- a/lua/Trans/conf/loader.lua
+++ b/lua/Trans/conf/loader.lua
@@ -45,15 +45,15 @@ M.load_conf = function(conf)
 
     pre_process()
     M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
-    local width = M.loaded_conf.style.window.cursor.float.width
-    local height = M.loaded_conf.style.window.cursor.float.height
+    local width = M.loaded_conf.style.window.float.width
+    local height = M.loaded_conf.style.window.float.height
 
     if width > 0 and width <= 1 then
-        M.loaded_conf.style.window.cursor.float.width = math.floor(width * vim.o.columns)
+        M.loaded_conf.style.window.float.width = math.floor(width * vim.o.columns)
     end
 
     if height > 0 and height <= 1 then
-        M.loaded_conf.style.window.cursor.float.height = math.floor(height * (vim.o.lines - vim.o.cmdheight))
+        M.loaded_conf.style.window.float.height = math.floor(height * (vim.o.lines - vim.o.cmdheight))
     end
 
     user_conf = nil
diff --git a/lua/Trans/core/backup.lua b/lua/Trans/core/backup.lua
new file mode 100644
index 0000000..fb8cd0e
--- /dev/null
+++ b/lua/Trans/core/backup.lua
@@ -0,0 +1,294 @@
+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
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
index f5ff007..71f91fa 100644
--- a/lua/Trans/core/process.lua
+++ b/lua/Trans/core/process.lua
@@ -1,21 +1,35 @@
 local type_check = require("Trans.util.debug").type_check
-local format = require("Trans.util.format")
 
 
--- NOTE : 将请求得到的字段进行处理
--- local offline_dir = debug.getinfo(1, "S").source:sub(2):match('.*Trans') .. '/component/offline'
+local function format(items, interval)
+
+end
+
+
 local function process (opts)
     type_check {
-        opts = { opts, 'table' }
+        opts = { opts, 'table' },
+        ['opts.field']  = { opts.field, 'table'  },
+        ['opts.order']  = { opts.order, 'table'  },
+        ['opts.win']    = { opts.win, 'table'    },
+        ['opts.engine'] = { opts.engine, 'table' },
     }
+
     local content = require('Trans.component.content'):new()
 
     for _, v in ipairs(opts.order) do
-        local component = format.format(opts.win_style, require("Trans.component" .. opts.engine .. v))
-        content:insert(component)
+        local items = format(require("Trans.component." .. opts.engine .. '.' .. v), 4)
+        content:insert(items)
     end
 
-    return content:lines()
+    local lines, __highlight = content:data()
+    vim.api.nvim_buf_set_lines(opts.bufnr, 0, lines)
+
+    for line, l_hl in ipairs(__highlight) do
+        for _, hl in ipairs(l_hl) do
+            vim.api.nvim_buf_add_highlight(opts.bufnr, line, hl.name, hl._start, hl._end)
+        end
+    end
 end
 
 
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
index ed53437..dac837a 100644
--- a/lua/Trans/core/query.lua
+++ b/lua/Trans/core/query.lua
@@ -1,7 +1,5 @@
-local M = {}
-
 local type_check = require("Trans.util.debug").type_check
-local query = require("Trans.database").query
+local query = require("Trans.api").query
 
 local function get_select()
     local s_start = vim.fn.getpos("'<")
@@ -14,44 +12,29 @@ local function get_select()
     return word
 end
 
-
-local function get_word(method)
-    if not method then
-        local mode = vim.api.nvim_get_mode()
-        if mode == 'n' then
-            return vim.fn.expand('<cword>')
-        elseif mode == 'v' then
-            return get_select()
-        else
-            error('invalid mode')
-        end
-    end
-
-    if method == 'input' then
-        return vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
-
-    -- TODO : other method
-    else
-        error('invalid method')
-    end
-end
-
-M.get_query_res = function(method)
+local query_wrapper = function(opts)
     type_check {
-        method = { method, 'string' },
+        opts = { opts, 'table' },
+        ['opts.method'] = { opts.method, 'string' },
     }
+
     local word = ''
-    if method == 'cursor' then
+
+    if opts.method == 'input' then
+        word = vim.fn.input('请输入您要查询的单词:') -- TODO Use Telescope with fuzzy finder
+
+    elseif opts.method == 'n' then
         word = vim.fn.expand('<cword>')
-    elseif method == 'select' then
-        word = get_select():match('%S+')
-    elseif method == 'input' then
+
+    elseif opts.mehotd == 'v' then
+        word = get_select()
+        -- TODO : other method
+
     else
-        error('unknown method')
+        error('invalid method' .. opts.method)
     end
 
     return query(word)
 end
 
-
-return M
+return query_wrapper
diff --git a/lua/Trans/core/show_win.lua b/lua/Trans/core/show_win.lua
index 7c17fa3..be06838 100644
--- a/lua/Trans/core/show_win.lua
+++ b/lua/Trans/core/show_win.lua
@@ -1,10 +1,5 @@
 local type_check = require("Trans.util.debug").type_check
 
-local buf_opts = {
-    filetype = 'Trans',
-    modifiable = false,
-}
-
 -- local win_opts = {
 --     winhl = 'Normal:TransWinNormal, FloatBorder:TransWinBorder'
 -- }
@@ -15,25 +10,22 @@ local function caculate_format(height, width)
     return row, col
 end
 
+
 local function show_win(opts)
     type_check {
         opts = { opts, 'table' },
         win = { opts.win, 'table' },
+        border = { opts.border, 'string' },
         highlight = { opts.highlight, 'table', true },
     }
 
-    local bufnr = vim.api.nvim_create_buf(false, true)
-    for k, v in pairs(buf_opts) do
-        vim.api.nvim_buf_set_option(bufnr, k, v)
-    end
-
     local is_float = opts.style == 'float'
     local win_opts = {
         relative = opts.style == 'float' and 'editor' or 'cursor',
         width = opts.width,
         height = opts.height,
         style = 'minimal',
-        border = 'rounded',
+        border = opts.border,
         title = 'Trans',
         title_pos = 'center',
         focusable = true,
@@ -45,8 +37,17 @@ local function show_win(opts)
         win_opts.row = 2
         win_opts.col = 2
     end
+
     local winid = vim.api.nvim_open_win(bufnr, is_float, win_opts)
 
+    vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, opts.lines)
+
+    for line, l_hl in ipairs(opts.highlight) do
+        for i, hl in ipairs(l_hl) do
+            vim.api.nvim_buf_add_highlight(bufnr, line, hl.name, i, hl._start, hl._end)
+        end
+    end
+
     return bufnr, winid
 end
 
diff --git a/lua/Trans/core/translate.lua b/lua/Trans/core/translate.lua
index fb8cd0e..af88e91 100644
--- a/lua/Trans/core/translate.lua
+++ b/lua/Trans/core/translate.lua
@@ -1,294 +1,110 @@
-local M          = {}
+-- Default conf
+local conf = require("Trans.conf.loader").loaded_conf
+local core = require("Trans.core")
 
 
-local opt = {
-    method = 'select',
-    view = 'cursor',
-}
+local function get_opts(opts)
+    local default_conf = {
+        method = vim.api.nvim_get_mode().mode,
+        engine = {
+            'local',
+            -- TODO : other engine
+        },
+        win = {
+            style = 'cursor',
+            width = conf.style.window.cursor.width,
+            height = conf.style.window.cursor.height
+        },
+    }
 
-M.Translate = function(opts)
-    local res = get_query_res(opts.method)
-    -- TODO <++>
+    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
 
--- M.Translate_online = function ()
---     -- TOOD
--- end
+-- EXAMPLE :
+-- require('Trans').translate({
+--     method = 'input', -- 不填则自动判断mode获取查询的单词
+--     engine = { -- 异步查询所有的引擎, 按照列表
+--         'offline',
+--         'youdao',
+--         'baidu'
+--     },
+--     -- win = 'cursor'
+--     win = {
+--         style = 'cursor',
+--         height = 50,
+--         width = 30,
+--     }
+-- })
 
 
--- 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
+local function create_win(opts)
+    local bufnr = vim.api.nvim_create_buf(false, true)
+    vim.api.nvim_buf_set_option(bufnr, 'filetype', 'Trans')
+    vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
+
+    local is_float = opts.style == 'float'
+    local win_opts = {
+        relative = is_float and 'editor' or 'cursor',
+        width = opts.width,
+        height = opts.height,
+        style = 'minimal',
+        border = conf.style.window[opts.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,
+        field = field,
+        order = conf.order['offline'],
+        engine = { 'offline' },
+        win_opts = opts.win,
+    }
+
+    core.process(proc_opts)
+end
+
+return translate
diff --git a/lua/Trans/init.lua b/lua/Trans/init.lua
index 380e4fb..317547b 100644
--- a/lua/Trans/init.lua
+++ b/lua/Trans/init.lua
@@ -1,7 +1,12 @@
 local M = {}
 
-M.setup = require('Trans.conf.loader').load_conf
+M.setup = function(opts)
+    require('Trans.conf.loader').load_conf(opts)
+    require("Trans.setup")
+    M.translate = require('Trans.core.translate')
+end
 
-M.translate = require('Tran.core.translate')
+M.translate = nil
+M.augroup = vim.api.nvim_create_augroup('Trans', {clear = true})
 
 return M
diff --git a/lua/Trans/setup.lua b/lua/Trans/setup.lua
index 9bf3250..2e0acb8 100644
--- a/lua/Trans/setup.lua
+++ b/lua/Trans/setup.lua
@@ -2,17 +2,24 @@ if vim.fn.executable('sqlite3') ~= 1 then
     error('Please check out sqlite3')
 end
 
-vim.api.nvim_create_user_command('TranslateCursorWord', require("Trans.core").query_cursor, {
-    desc = '翻译光标下的单词',
-})
-vim.api.nvim_create_user_command('TranslateSelectWord', require("Trans.core").query_select, {
-    desc = '翻译选中的单词',
-})
-vim.api.nvim_create_user_command('TranslateInputWord', require("Trans.core").query_input, {
-    desc = '翻译输入的单词',
+vim.api.nvim_create_user_command('Translate', function ()
+    require("Trans").translate()
+end, {
+    desc = '翻译单词',
 })
 
-local highlights = require("Trans.conf").ui.highligh
+vim.api.nvim_create_user_command('TranslateInput', function ()
+    require("Trans").translate {
+        method = 'input',
+    }
+end, {desc = '翻译单词'})
+
+-- 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.nvim_set_hl(0, highlight, opt)
+    vim.api.nvim_set_hl(0, highlight, opt)
 end
diff --git a/lua/Trans/util/debug.lua b/lua/Trans/util/debug.lua
index 58cb855..3088acd 100644
--- a/lua/Trans/util/debug.lua
+++ b/lua/Trans/util/debug.lua
@@ -1,17 +1,14 @@
 local M = {}
 
 -- INFO : get loaded debug conf
-local base = require("Trans.conf.loader").loaded_conf.base
-local debug = require("Trans.conf.default").conf.base.debug
-if base and base.debug then
-    debug = vim.tbl_extend('force', debug, base)
-end
+local type_check = true
 
 M.type_check = function (types)
-    if debug.enable and debug.type_check then
+    if type_check then
         vim.validate(types)
     end
 end
+
 -- local function dedent(lines)
 --     local ind_size = math.huge
 --     for i, _ in ipairs(lines) do
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index e3c520d..bdc4bec 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -143,10 +143,10 @@ end
 
 ---@alias formatted_items table
 ---将组件格式化成相应的vim支持的lines格式
----@param style string 窗口的风格
+---@param win_size string 窗口的宽度和高度
 ---@param component table 需要格式化的字段
 ---@return formatted_items[] lines
-M.format = function(style, component)
+M.format = function(win_width, component)
     type_check {
         style = { style, { 'string' } },
         component = { component, { 'table' } },
@@ -161,19 +161,16 @@ M.format = function(style, component)
         length = length + width
     end
 
-    m_win_width  = style_width[style] - m_indent
+    m_win_width  = win_width
     m_fields     = fields
     m_size       = #m_fields
     m_tot_width  = length
     m_item_width = item_size
-    m_interval   = m_win_width > 50 and 6 or 4
 
     return formatted_lines()
 end
 
 
-
-
 ---合并多个数组, 第一个数组将会被使用
 ---@param ... string[] 需要被合并的数组
 ---@return table res   合并后的数组
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
index fa4d1e9..7fa1b76 100644
--- a/lua/Trans/util/test/test.lua
+++ b/lua/Trans/util/test/test.lua
@@ -1,5 +1,8 @@
-local a = nil
+local a = 'test'
 
 
+local b = a
 
-print((' '):rep(a))
+b = b .. 'test'
+
+print(a, b)
diff --git a/lua/Trans/wrapper/translate.lua b/lua/Trans/wrapper/translate.lua
deleted file mode 100644
index 4cbffd3..0000000
--- a/lua/Trans/wrapper/translate.lua
+++ /dev/null
@@ -1,67 +0,0 @@
-local type_check = require("Trans.util.debug").type_check
--- Default conf
-local conf = require("Trans.conf.loader").loaded_conf
-local core = require("Trasn.core")
-
-
-local function get_opts(opts)
-    local default_conf = {
-        method = vim.api.nvim_get_mode(),
-        engine = {
-            'local',
-            -- TODO : other engine
-        },
-        win = {
-            style = 'cursor',
-            width = conf.window.cursor.width,
-            height = conf.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
-
-local function translate(opts)
-    type_check {
-        opts = { opts, 'table' }
-    }
-
-    --- TODO : 异步请求
-    -- NOTE : 这里只处理了本地的请求
-    opts = get_opts(opts or {})
-    local field = core.query(opts)
-
-    local proc_opts = {
-        field = field,
-        order = conf.order['offline'],
-        engine = 'offline',
-        win_style = opts.win.style,
-    }
-
-    local content, highlight = core.process(proc_opts)
-
-    local win_opts = {
-        win = opts.win,
-        content = content,
-        highlight = highlight,
-    }
-
-    core.show_win(win_opts)
-end
-
-return translate

From 671e3cc7e76cad99dc43beba57dffdb7737e972a Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Mon, 9 Jan 2023 23:49:16 +0800
Subject: [PATCH 13/17] feat: add more bugs

---
 lua/Trans/component/content.lua |  1 +
 lua/Trans/component/items.lua   | 20 ++++++++++++++++++++
 lua/Trans/core/process.lua      | 17 ++++++++++-------
 lua/Trans/util/test/test.lua    | 10 +++++-----
 4 files changed, 36 insertions(+), 12 deletions(-)
 create mode 100644 lua/Trans/component/items.lua

diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 3c6f907..86c7e3b 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -38,6 +38,7 @@ function M:insert(items)
         indent = items.indent,
         highlight = items.highlight,
     }
+
     local highlight = {}
 
 
diff --git a/lua/Trans/component/items.lua b/lua/Trans/component/items.lua
new file mode 100644
index 0000000..d1c775e
--- /dev/null
+++ b/lua/Trans/component/items.lua
@@ -0,0 +1,20 @@
+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
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
index 71f91fa..dd2ef48 100644
--- a/lua/Trans/core/process.lua
+++ b/lua/Trans/core/process.lua
@@ -1,25 +1,28 @@
 local type_check = require("Trans.util.debug").type_check
 
 
-local function format(items, interval)
 
+local function format(component, interval)
 end
 
 
 local function process (opts)
     type_check {
         opts = { opts, 'table' },
-        ['opts.field']  = { opts.field, 'table'  },
-        ['opts.order']  = { opts.order, 'table'  },
-        ['opts.win']    = { opts.win, 'table'    },
-        ['opts.engine'] = { opts.engine, 'table' },
+        ['opts.field']  = { opts.field  , 'table' },
+        ['opts.order']  = { opts.order  , 'table' },
+        ['opts.win']    = { opts.win    , 'table' },
+        ['opts.engine'] = { opts.engine , 'table' },
     }
 
     local content = require('Trans.component.content'):new()
 
     for _, v in ipairs(opts.order) do
-        local items = format(require("Trans.component." .. opts.engine .. '.' .. v), 4)
-        content:insert(items)
+        local component = require("Trans.component." .. opts.engine .. '.' .. v)
+        for _, items in ipairs(component) do
+            format(items)
+            content:insert(items)
+        end
     end
 
     local lines, __highlight = content:data()
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
index 7fa1b76..a5bd3c3 100644
--- a/lua/Trans/util/test/test.lua
+++ b/lua/Trans/util/test/test.lua
@@ -1,8 +1,8 @@
-local a = 'test'
+local a = {
+    'test1',
+    'test2',
+    'test3'
+}
 
 
-local b = a
-
-b = b .. 'test'
-
 print(a, b)

From 1b95485ae68439e1833a30e32cecb731cfb66973 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Tue, 10 Jan 2023 14:40:28 +0800
Subject: [PATCH 14/17] fix: try reducing some bugs

---
 lua/Trans/component/content.lua       |   1 +
 lua/Trans/component/offline/Title.lua |  21 ++--
 lua/Trans/conf/default.lua            |   2 +-
 lua/Trans/core/process.lua            | 132 +++++++++++++++++++++++---
 lua/Trans/core/translate.lua          |  16 ++--
 lua/Trans/util/format.lua             |   1 -
 lua/Trans/util/test/query_youdao.lua  |  23 +++--
 lua/Trans/util/test/test.lua          |  12 ++-
 8 files changed, 163 insertions(+), 45 deletions(-)

diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 86c7e3b..7adc86a 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -69,6 +69,7 @@ function M:data()
     -- NOTE 返回格式化的行,如果需要高亮,则第二个参数返回高亮
     local lines = {}
     local highlights = {}
+
     for index = 1, #self.lines do
         local line = ''
         local highlight = {}
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index d02eb69..c1203a8 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -37,15 +37,15 @@ local icon = require("Trans.conf.loader").loaded_conf.ui.icon
 ---@return component component 提取的组件信息[包含多个组件]
 M.component = function(field)
     local component = {}
-    local stuffs = {}
     local data = {
-        {field.word, 'TransWord'},
+        { field.word, 'TransWord' },
     }
 
-    if display.phonetic and field.phonetic then
-        table.insert(data, {
-            '[' .. field.phonetic .. ']', 'TransPhonetic'
-        })
+    if display.phnoetic and field.phonetic ~= '' then
+        table.insert(
+            data,
+            { '[' .. field.phonetic .. ']', 'TransPhonetic' }
+        )
     end
 
     if display.collins and field.collins then
@@ -55,13 +55,12 @@ M.component = function(field)
     end
 
     if display.oxford and field.oxford then
-        table.insert(data, {
-            field.oxford
-        })
+        table.insert(data,
+            { field.oxford == 1 and icon.isOxford or icon.notOxford, }
+        )
     end
 
-    stuffs.data = data
-    component[1] = stuffs
+    component[1] = data
     return component
 end
 
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 5e92c18..4518665 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -75,7 +75,7 @@ M.conf = {
         },
         display = {
             phnoetic = true,
-            collins_star = true,
+            collins = true,
             oxford = true,
             -- TODO
             -- history = false,
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
index dd2ef48..82df19b 100644
--- a/lua/Trans/core/process.lua
+++ b/lua/Trans/core/process.lua
@@ -1,39 +1,145 @@
 local type_check = require("Trans.util.debug").type_check
 
+-- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
+-- 为了解决中文字符在lua的长度和neovim显示不一致的问题
+local function get_width(str)
+    if type(str) ~= 'string' then
+        vim.pretty_print(str)
+        error('str!')
+    end
+    return vim.fn.strdisplaywidth(str)
+end
+
+local function format(win_width, items)
+    table.sort(items, function(a, b)
+        local wa, wb = 0, 0
+        if type(a) == 'string' then
+            wa = get_width(a)
+            a = { a }
+        else
+            wa = get_width(a[1])
+        end
+        if type(b) == 'string' then
+            wb = get_width(b)
+            b = { b }
+        else
+            wb = get_width(b[1])
+        end
+        return wa > wb
+    end)
+
+    local size = #items
+    local width = win_width - get_width(items[1][1])
+    local cols = 0
+    for i = 2, size do
+        width = width - 4 - get_width(items[i][1])
+        if width < 0 then
+            cols = i
+            break
+        end
+    end
 
 
-local function format(component, interval)
+    if cols == 0 then
+        return items
+    else
+        local lines = {}
+        local rows = math.floor(size / cols)
+        local rest = size % cols
+        if rest == 0 then
+            rest = cols
+        end
+
+        local max_width = get_width(items[1][1])
+        for i = 1, rows do
+            local index = rows - i + 1
+            lines[index] = {
+                interval = items.interval,
+                highlight = items.highlight,
+                indent = items.indent,
+            }
+
+            items[i][1] = items[i][1] .. (' '):rep(max_width - get_width(items[i][1]))
+            lines[index][1] = items[i]
+        end
+
+        local index = rows + 1
+        for col = 2, cols do
+            max_width = get_width(items[index])
+            local _end = col > rest and rows - 1 or rows
+
+            for i = 1, _end do
+                local idx = _end - i + 1 -- 当前操作的行数
+                local item_idx = index + i - 1
+                local item = items[item_idx]
+                item[1] = item[1] .. (' '):rep(max_width - get_width(item[1]))
+
+
+                lines[idx][col] = item
+            end
+            index = index + _end
+        end
+
+        return lines
+    end
 end
 
 
-local function process (opts)
+local function process(opts)
     type_check {
-        opts = { opts, 'table' },
-        ['opts.field']  = { opts.field  , 'table' },
-        ['opts.order']  = { opts.order  , 'table' },
-        ['opts.win']    = { opts.win    , 'table' },
-        ['opts.engine'] = { opts.engine , 'table' },
+        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 = {'no tranlation'}
+        vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, false, lines)
+        return
+    end
+
+
     local content = require('Trans.component.content'):new()
 
     for _, v in ipairs(opts.order) do
-        local component = require("Trans.component." .. opts.engine .. '.' .. v)
+        local component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v).component(opts.field)
+        -- vim.pretty_print(component)
+
         for _, items in ipairs(component) do
-            format(items)
-            content:insert(items)
+            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
         end
     end
 
     local lines, __highlight = content:data()
-    vim.api.nvim_buf_set_lines(opts.bufnr, 0, lines)
+    vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, false, lines)
+
 
     for line, l_hl in ipairs(__highlight) do
         for _, hl in ipairs(l_hl) do
-            vim.api.nvim_buf_add_highlight(opts.bufnr, line, hl.name, hl._start, hl._end)
+            vim.api.nvim_buf_add_highlight(opts.bufnr, -1, hl.name, line, hl._start, hl._end)
         end
     end
+    vim.api.nvim_buf_set_option(opts.bufnr, 'modifiable', false)
+    vim.api.nvim_buf_set_option(opts.bufnr, 'filetype', 'Trans')
+    if opts.win.style == 'cursor' then
+        vim.api.nvim_create_autocmd(
+            { 'InsertEnter', 'CursorMoved', 'BufLeave', }, {
+            buffer = 0,
+            once = true,
+            callback = function ()
+                vim.api.nvim_win_close(opts.winid, true)
+            end,
+        })
+    end
 end
 
-
 return process
diff --git a/lua/Trans/core/translate.lua b/lua/Trans/core/translate.lua
index af88e91..b66b3c2 100644
--- a/lua/Trans/core/translate.lua
+++ b/lua/Trans/core/translate.lua
@@ -7,7 +7,7 @@ local function get_opts(opts)
     local default_conf = {
         method = vim.api.nvim_get_mode().mode,
         engine = {
-            'local',
+            'offline',
             -- TODO : other engine
         },
         win = {
@@ -52,18 +52,16 @@ end
 -- })
 
 
-local function create_win(opts)
+local function create_win(win)
     local bufnr = vim.api.nvim_create_buf(false, true)
-    vim.api.nvim_buf_set_option(bufnr, 'filetype', 'Trans')
-    vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
 
-    local is_float = opts.style == 'float'
+    local is_float = win.style == 'float'
     local win_opts = {
         relative = is_float and 'editor' or 'cursor',
-        width = opts.width,
-        height = opts.height,
+        width = win.width,
+        height = win.height,
         style = 'minimal',
-        border = conf.style.window[opts.win.style].border,
+        border = conf.style.window[win.style].border,
         title = 'Trans',
         title_pos = 'center',
         focusable = true,
@@ -98,10 +96,10 @@ local function translate(opts)
     local proc_opts = {
         bufnr = bufnr,
         winid = winid,
+        win = opts.win,
         field = field,
         order = conf.order['offline'],
         engine = { 'offline' },
-        win_opts = opts.win,
     }
 
     core.process(proc_opts)
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
index bdc4bec..b9c62fe 100644
--- a/lua/Trans/util/format.lua
+++ b/lua/Trans/util/format.lua
@@ -7,7 +7,6 @@ function string:width()
     return vim.fn.strdisplaywidth(self)
 end
 
-
 local s_to_b = true -- 从小到大排列
 
 local m_win_width -- 需要被格式化窗口的高度
diff --git a/lua/Trans/util/test/query_youdao.lua b/lua/Trans/util/test/query_youdao.lua
index 1d064f8..8653e25 100644
--- a/lua/Trans/util/test/query_youdao.lua
+++ b/lua/Trans/util/test/query_youdao.lua
@@ -43,16 +43,21 @@ end
 -- curl --data {{'{"name":"bob"}'}} --header {{'Content-Type: application/json'}} {{http://example.com/users/1234}}
 
 local function query_word(q)
-    local field = (
-        [[curl -s --header 'Content-Type: application/x-www-form-urlencoded' https://openapi.youdao.com/api]])
-    for k, v in pairs(q) do
-        field = field .. ([[ -d '%s=%s']]):format(k, v)
+    local ok, curl = pcall(require, 'plenary.curl')
+    if ok then
+        -- TODO 
+    else
+        local field = (
+            [[curl -s --header 'Content-Type: application/x-www-form-urlencoded' https://openapi.youdao.com/api]])
+
+        for k, v in pairs(q) do
+            field = field .. ([[ -d '%s=%s']]):format(k, v)
+        end
+
+        local output = vim.fn.system(field)
+        local tb = vim.fn.json_decode(output)
+        return tb
     end
-    -- vim.pretty_print(field)
-    local output = vim.fn.system(field)
-    local tb = vim.fn.json_decode(output)
-    -- print(type(output))
-    -- vim.pretty_print(tb.basic)
 end
 
 M.test = function(query)
diff --git a/lua/Trans/util/test/test.lua b/lua/Trans/util/test/test.lua
index a5bd3c3..72af591 100644
--- a/lua/Trans/util/test/test.lua
+++ b/lua/Trans/util/test/test.lua
@@ -5,4 +5,14 @@ local a = {
 }
 
 
-print(a, b)
+local function test(tmp)
+    tmp = {
+        'bbbbbb'
+    }
+end
+
+
+test(a)
+for i, v in ipairs(a) do
+    print(v)
+end

From a57a6e47ab25a388257e50c61d38fce465f1e3e2 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Tue, 10 Jan 2023 17:51:07 +0800
Subject: [PATCH 15/17] fix: fix format and process function behaviours

---
 lua/Trans/component/content.lua             |  45 ++++-
 lua/Trans/component/offline/Definition.lua  |   2 +-
 lua/Trans/component/offline/Exchange.lua    |   2 +-
 lua/Trans/component/offline/Pos.lua         |   2 +-
 lua/Trans/component/offline/Tag.lua         |  44 ++++-
 lua/Trans/component/offline/Title.lua       |  12 +-
 lua/Trans/component/offline/Translation.lua |   2 +-
 lua/Trans/conf/default.lua                  |  21 ++-
 lua/Trans/core/README.md                    |   2 +-
 lua/Trans/core/process.lua                  | 151 ++++++++--------
 lua/Trans/core/query.lua                    |  21 ++-
 lua/Trans/core/translate.lua                |   4 +
 lua/Trans/util/format.lua                   | 190 --------------------
 lua/Trans/util/parser.lua                   |  19 --
 14 files changed, 193 insertions(+), 324 deletions(-)
 delete mode 100644 lua/Trans/util/format.lua
 delete mode 100644 lua/Trans/util/parser.lua

diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 7adc86a..9960e2d 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -3,7 +3,9 @@ local type_check = require("Trans.util.debug").type_check
 M.__index = M
 M.lines = {}
 M.highlight = {}
-M.size = 0
+M.height = 0
+M.width = 0
+M.interval = '    '
 
 
 function M:new()
@@ -31,10 +33,9 @@ function M:insert(items)
         items = { items, 'table' },
     }
 
-    self.size = self.size + 1 -- line数加一
+    self.height = self.height + 1 -- line数加一
 
     local line = {
-        space = (' '):rep(items.interval),
         indent = items.indent,
         highlight = items.highlight,
     }
@@ -52,8 +53,8 @@ function M:insert(items)
         end
     end
 
-    self.highlight[self.size] = highlight
-    self.lines[self.size] = line
+    self.highlight[self.height] = highlight
+    self.lines[self.height] = line
 end
 
 ---Usage:
@@ -78,9 +79,11 @@ function M:data()
         if l.indent then
             line = (' '):rep(l.indent)
         end
+
         if l.highlight then
-            line = line .. table.concat(l, l.space)
+            line = line .. table.concat(l, self.interval)
             highlight[1] = { name = l.highlight, _start = 1, _end = -1 }
+
         else
             line = line .. l[1]
 
@@ -90,7 +93,7 @@ function M:data()
             end
 
             for i = 2, #l do
-                line = line .. l.space .. l[i]
+                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 })
@@ -98,11 +101,37 @@ function M:data()
             end
         end
 
-        -- return line, highlights
         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(bufnr, winid)
+    local height = vim.api.nvim_win_get_height(winid)
+    local width = vim.api.nvim_win_get_width(winid)
+
+    vim.api.nvim_win_set_height(winid, self.height)
+    local lines, hls = self:data()
+    vim.api.nvim_buf_set_lines(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(bufnr, -1, hl.name, line - 1, hl._start, hl._end)
+        end
+    end
+
+    if self.height < height then
+        vim.api.nvim_win_set_height(winid, self.height)
+    end
+
+    if self.width < width then
+        vim.api.nvim_win_set_width(winid, self.width)
+    end
+end
+
 return M
diff --git a/lua/Trans/component/offline/Definition.lua b/lua/Trans/component/offline/Definition.lua
index 94acd96..e557040 100644
--- a/lua/Trans/component/offline/Definition.lua
+++ b/lua/Trans/component/offline/Definition.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_content = function (field)
+M.component = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Exchange.lua b/lua/Trans/component/offline/Exchange.lua
index 94acd96..e557040 100644
--- a/lua/Trans/component/offline/Exchange.lua
+++ b/lua/Trans/component/offline/Exchange.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_content = function (field)
+M.component = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Pos.lua b/lua/Trans/component/offline/Pos.lua
index 94acd96..e557040 100644
--- a/lua/Trans/component/offline/Pos.lua
+++ b/lua/Trans/component/offline/Pos.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_content = function (field)
+M.component = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/component/offline/Tag.lua b/lua/Trans/component/offline/Tag.lua
index 94acd96..a95080f 100644
--- a/lua/Trans/component/offline/Tag.lua
+++ b/lua/Trans/component/offline/Tag.lua
@@ -1,7 +1,47 @@
 local M = {}
 
-M.to_content = function (field)
-    -- TODO 
+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,
+        }
+
+        for _tag in vim.gsplit(field.tag, ' ', true) do
+            if _tag ~= '' then
+                local tag = tag_map[_tag]
+
+                if tag then
+                    table.insert(tags, tag)
+                else
+                    error('add tag_map for [' .. _tag .. ']')
+                end
+            end
+        end
+
+        return { ref, tags }
+    end
 end
 
+
 return M
diff --git a/lua/Trans/component/offline/Title.lua b/lua/Trans/component/offline/Title.lua
index c1203a8..3613893 100644
--- a/lua/Trans/component/offline/Title.lua
+++ b/lua/Trans/component/offline/Title.lua
@@ -25,13 +25,13 @@ local icon = require("Trans.conf.loader").loaded_conf.ui.icon
 --     -- { phonetic, 'TransPhonetic' },
 -- }
 
----@alias stuff
----| 'data'       # 所有组件的信息
+
+---@alias items
+---| 'string[]'       # 所有组件的信息
+---| 'needformat?'# 是否需要格式化
 ---| 'highlight?' # 整个组件的高亮
 ---| 'indent?'    # 每行整体的缩进
----| 'interval?'  # 每个组件的间隔
----@alias component stuff[]
-
+---@alias component items[]
 ---从查询结果中获取字符串
 ---@param field table 查询的结果
 ---@return component component 提取的组件信息[包含多个组件]
@@ -41,7 +41,7 @@ M.component = function(field)
         { field.word, 'TransWord' },
     }
 
-    if display.phnoetic and field.phonetic ~= '' then
+    if display.phnoetic and field.phonetic and field.phonetic ~= '' then
         table.insert(
             data,
             { '[' .. field.phonetic .. ']', 'TransPhonetic' }
diff --git a/lua/Trans/component/offline/Translation.lua b/lua/Trans/component/offline/Translation.lua
index 94acd96..e557040 100644
--- a/lua/Trans/component/offline/Translation.lua
+++ b/lua/Trans/component/offline/Translation.lua
@@ -1,6 +1,6 @@
 local M = {}
 
-M.to_content = function (field)
+M.component = function (field)
     -- TODO 
 end
 
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 4518665..39fddc7 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -10,8 +10,8 @@ M.conf = {
         window = {
             cursor = {
                 border = 'rounded',
-                width = 30,
-                height = 30,
+                width = 40,
+                height = 20,
             },
             float = {
                 border = 'rounded',
@@ -29,11 +29,11 @@ M.conf = {
     order = {
         offline = {
             'Title',
-            -- 'Tag',
-            -- 'Pos',
-            -- 'Exchange',
-            -- 'Translation',
-            -- 'Definition',
+            'Tag',
+            'Pos',
+            'Exchange',
+            'Translation',
+            'Definition',
         },
         -- online = {
         --     -- TODO 
@@ -67,6 +67,13 @@ M.conf = {
             TransDefinition = {
                 fg = '#bc8cff',
             },
+            TransCursorWin = {
+                link = 'Normal',
+            },
+
+            TransCursorBorder = {
+                link = 'FloatBorder',
+            }
         },
         icon = {
             star = '⭐',
diff --git a/lua/Trans/core/README.md b/lua/Trans/core/README.md
index 5fa3070..fda9162 100644
--- a/lua/Trans/core/README.md
+++ b/lua/Trans/core/README.md
@@ -69,7 +69,7 @@
         - `vsplit` 在左边或者右边分屏
 
     - 高度(height):
-        - `value > 1` 实际高度
+        - `value > 1` 最大高度
         - `0 <= value <= 1` 相对高度
         - `0 < value` 无限制
 
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
index 82df19b..b94a105 100644
--- a/lua/Trans/core/process.lua
+++ b/lua/Trans/core/process.lua
@@ -2,141 +2,136 @@ local type_check = require("Trans.util.debug").type_check
 
 -- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
 -- 为了解决中文字符在lua的长度和neovim显示不一致的问题
-local function get_width(str)
-    if type(str) ~= 'string' then
-        vim.pretty_print(str)
-        error('str!')
-    end
-    return vim.fn.strdisplaywidth(str)
-end
+local get_width = vim.fn.strdisplaywidth
 
 local function format(win_width, items)
-    table.sort(items, function(a, b)
-        local wa, wb = 0, 0
-        if type(a) == 'string' then
-            wa = get_width(a)
-            a = { a }
-        else
-            wa = get_width(a[1])
-        end
-        if type(b) == 'string' then
-            wb = get_width(b)
-            b = { b }
-        else
-            wb = get_width(b[1])
-        end
-        return wa > wb
-    end)
-
     local size = #items
-    local width = win_width - get_width(items[1][1])
-    local cols = 0
-    for i = 2, size do
-        width = width - 4 - get_width(items[i][1])
-        if width < 0 then
-            cols = i
-            break
+    local tot_width = 0
+
+    for i = 1, size do
+        if type(items[i]) == 'string' then
+            items[i] = { items[i] }
         end
+        tot_width = tot_width + get_width(items[i][1]) + 4
     end
 
 
-    if cols == 0 then
-        return items
-    else
+    -- 判断宽度是否超过最大宽度
+    if tot_width > win_width + 4 then
+        -- 放不下则需要分成多行
         local lines = {}
-        local rows = math.floor(size / cols)
+
+        -- 行内字符串按照宽度排序
+        table.sort(items, function(a, b)
+            return get_width(a[1]) > get_width(b[1])
+        end)
+
+        local cols = 1
+        win_width = win_width - get_width(items[1][1])
+        while win_width > 0 and cols < size do
+            cols = cols + 1
+            win_width = win_width - get_width(items[cols][1]) + 4
+        end
+        cols = cols - 1
+
+        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])
-        for i = 1, rows do
-            local index = rows - i + 1
-            lines[index] = {
-                interval = items.interval,
+        local index = 1 -- 当前操作的字符串下标
+        for i = rows, 1, -1 do -- 当前操作的行号
+            lines[i] = {
                 highlight = items.highlight,
                 indent = items.indent,
             }
 
-            items[i][1] = items[i][1] .. (' '):rep(max_width - get_width(items[i][1]))
-            lines[index][1] = items[i]
+            local item = items[index]
+            item[1] = item[1] .. (' '):rep(max_width - get_width(item[1]))
+            lines[i][1] = items[index]
+            index = index + 1
         end
 
-        local index = rows + 1
+
         for col = 2, cols do
-            max_width = get_width(items[index])
+            max_width = get_width(items[index][1])
             local _end = col > rest and rows - 1 or rows
 
-            for i = 1, _end do
-                local idx = _end - i + 1 -- 当前操作的行数
-                local item_idx = index + i - 1
-                local item = items[item_idx]
+            for i = _end, 1, -1 do
+                local item = items[index]
                 item[1] = item[1] .. (' '):rep(max_width - get_width(item[1]))
 
 
-                lines[idx][col] = item
+                lines[i][col] = item
+                index = index + 1
             end
-            index = index + _end
         end
 
-        return lines
+        return lines, true
+    else
+        return items
     end
 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.win']    = { opts.win, 'table' },
         ['opts.engine'] = { opts.engine, 'table' },
     }
 
     if opts.field == nil then
-        local lines = {'no tranlation'}
+        local lines = { '⚠️   本地没有找到相关释义' }
         vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, false, lines)
-        return
-    end
+        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()
+        for _, v in ipairs(opts.order) do
+            local component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v).component(opts.field)
+            if component then
+                for _, items in ipairs(component) do
 
-    local content = require('Trans.component.content'):new()
+                    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
 
-    for _, v in ipairs(opts.order) do
-        local component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v).component(opts.field)
-        -- vim.pretty_print(component)
+                    else
+                        content:insert(items)
+                    end
 
-        for _, items in ipairs(component) do
-            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
+
         end
+
+        content:attach(opts.bufnr, opts.winid)
+
     end
 
-    local lines, __highlight = content:data()
-    vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, false, lines)
-
-
-    for line, l_hl in ipairs(__highlight) do
-        for _, hl in ipairs(l_hl) do
-            vim.api.nvim_buf_add_highlight(opts.bufnr, -1, hl.name, line, hl._start, hl._end)
-        end
-    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, '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 ()
-                vim.api.nvim_win_close(opts.winid, true)
+            callback = function()
+                if vim.api.nvim_win_is_valid(opts.winid) then
+                    vim.api.nvim_win_close(opts.winid, true)
+                end
             end,
         })
     end
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
index dac837a..c973f44 100644
--- a/lua/Trans/core/query.lua
+++ b/lua/Trans/core/query.lua
@@ -2,14 +2,17 @@ local type_check = require("Trans.util.debug").type_check
 local query = require("Trans.api").query
 
 local function get_select()
-    local s_start = vim.fn.getpos("'<")
-    local s_end = vim.fn.getpos("'>")
-    if s_start[2] ~= s_start[2] then
-        error('TODO: multiline translate')
+    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
-    local lin = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)[1]
-    local word = string.sub(lin, s_start[3], s_end[3])
-    return word
+    return table.concat(lines, '\n')
 end
 
 local query_wrapper = function(opts)
@@ -21,15 +24,15 @@ local query_wrapper = function(opts)
     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.mehotd == 'v' then
+    elseif opts.method == 'v' then
         word = get_select()
         -- TODO : other method
-
     else
         error('invalid method' .. opts.method)
     end
diff --git a/lua/Trans/core/translate.lua b/lua/Trans/core/translate.lua
index b66b3c2..f336240 100644
--- a/lua/Trans/core/translate.lua
+++ b/lua/Trans/core/translate.lua
@@ -21,6 +21,7 @@ local function get_opts(opts)
         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
@@ -35,6 +36,7 @@ local function get_opts(opts)
     return vim.tbl_extend('force', default_conf, opts)
 end
 
+
 -- EXAMPLE :
 -- require('Trans').translate({
 --     method = 'input', -- 不填则自动判断mode获取查询的单词
@@ -52,6 +54,7 @@ end
 -- })
 
 
+
 local function create_win(win)
     local bufnr = vim.api.nvim_create_buf(false, true)
 
@@ -81,6 +84,7 @@ local function create_win(win)
     return bufnr, winid
 end
 
+
 local function translate(opts)
     vim.validate {
         opts = { opts, 'table', true }
diff --git a/lua/Trans/util/format.lua b/lua/Trans/util/format.lua
deleted file mode 100644
index b9c62fe..0000000
--- a/lua/Trans/util/format.lua
+++ /dev/null
@@ -1,190 +0,0 @@
-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 s_to_b = true -- 从小到大排列
-
-local m_win_width -- 需要被格式化窗口的高度
-local m_fields -- 待格式化的字段
-local m_tot_width -- 所有字段加起来的长度(不包括缩进和间隔)
-local m_item_width -- 每个字段的宽度
-local m_interval -- 每个字段的间隔
-local m_size -- 字段的个数
-
-local function caculate_format()
-    local width = m_win_width - m_item_width[1]
-    local cols = 0
-    for i = 2, m_size 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_size / 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() -- 需要按照width排序
-    end)
-end
-
-local function format_to_multilines(rows, cols)
-    local lines = {}
-
-    local rest = m_size % cols
-    if rest == 0 then
-        rest = cols
-    end
-
-    local s_width = m_item_width[1] -- 列中最宽的字符串宽度
-    for i = 1, rows do
-        local idx = s_to_b and rows - i + 1 or i
-        lines[idx] = {}
-
-        local space = (' '):rep(s_width - m_item_width[i])
-        local item = m_fields[i] .. space
-
-        lines[idx][1] = item
-        lines[idx].interval = m_interval
-    end
-
-
-    local index = rows + 1 -- 最宽字符的下标
-
-    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_idx = index + i - 1 -- 当前操作的字段数
-            local space    = (' '):rep(s_width - m_item_width[item_idx]) -- 对齐空格
-            local item     = m_fields[item_idx] .. space
-
-            lines[idx][j] = item -- 插入图标
-        end
-        index = index + stop -- 更新最宽字符的下标
-    end
-
-    return lines -- TODO : evaluate the width
-end
-
-local function formatted_lines()
-    local lines = {}
-    -- NOTE : 判断能否格式化成一行
-    if m_tot_width + (m_size * m_indent) > m_win_width then
-        sort_tables()
-        --- NOTE : 计算应该格式化成多少行和列
-        local rows, cols = caculate_format()
-        lines = format_to_multilines(rows, cols)
-    else
-        lines[1] = format_to_line()
-    end
-
-    return lines
-end
-
--- EXAMPLE : 接受的形式
--- local content = {
---     { word, 'TransWord' },
---     { phonetic, 'TransPhonetic' },
---     collins,
---     oxford
---     -- { phonetic, 'TransPhonetic' },
---  NOTE :
--- 可选的:
--- 1. highlight 整个content的高亮
--- 2. indent    缩进
--- 2. space     各个组件的及间隔
--- }
-
-
--- EXAMPLE : 返回的形式
--- local lines = {
---     { items, opts },
---     { items, opts },
---     { items, opts },
---     -- items: string[]
---     -- opts {
---     --     highlight
---     --     indent
---     -- }
--- }
-
-
----@alias formatted_items table
----将组件格式化成相应的vim支持的lines格式
----@param win_size string 窗口的宽度和高度
----@param component table 需要格式化的字段
----@return formatted_items[] lines
-M.format = function(win_width, component)
-    type_check {
-        style = { style, { 'string' } },
-        component = { component, { 'table' } },
-    }
-
-    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_win_width  = win_width
-    m_fields     = fields
-    m_size       = #m_fields
-    m_tot_width  = length
-    m_item_width = item_size
-
-    return formatted_lines()
-end
-
-
----合并多个数组, 第一个数组将会被使用
----@param ... string[] 需要被合并的数组
----@return table res   合并后的数组
-M.extend_array = function(...)
-    local arrays = { ... }
-    local res = arrays[1]
-    local index = #res
-    for i = 2, #arrays do
-        for _, value in ipairs(arrays[i]) do
-            res[index] = value
-            index = index + 1
-        end
-    end
-    return res
-end
-
-
-return M
diff --git a/lua/Trans/util/parser.lua b/lua/Trans/util/parser.lua
deleted file mode 100644
index 4c4adfc..0000000
--- a/lua/Trans/util/parser.lua
+++ /dev/null
@@ -1,19 +0,0 @@
----@diagnostic disable: missing-return, unused-local
-local M = {}
-local type_check = require("Trans.util.debug").type_check
-
----解析宽度
----@param width integer
----@return integer
-M.width = function (width)
-    -- TODO 
-end
-
----解析宽度
----@param height integer
----@return integer
-M.height = function (height)
-    -- TODO 
-end
-
-return M

From 32eeae88d470102a8460922d1e963f165033cfc3 Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Tue, 10 Jan 2023 18:55:21 +0800
Subject: [PATCH 16/17] feat: reduce bugs

---
 lua/Trans/conf/window.lua   | 61 -------------------------------------
 lua/Trans/core/init.lua     |  2 +-
 lua/Trans/core/show_win.lua | 54 --------------------------------
 3 files changed, 1 insertion(+), 116 deletions(-)
 delete mode 100644 lua/Trans/conf/window.lua
 delete mode 100644 lua/Trans/core/show_win.lua

diff --git a/lua/Trans/conf/window.lua b/lua/Trans/conf/window.lua
deleted file mode 100644
index c81af89..0000000
--- a/lua/Trans/conf/window.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-local M = {}
-local conf = require("Trans.conf.loader").loaded_conf.style.window
-local type_check = require("Trans.util.debug").type_check
-
--- FIXME 
-
-local get_float_opts = function(float_conf)
-    type_check {
-        float_conf = { float_conf, 'table' },
-    }
-    local columns = vim.o.columns
-    local height = vim.o.lines - vim.o.cmdheight - float_conf.top_offset
-    local width = math.floor(columns * float_conf.relative_width)
-
-    return {
-        relative = 'editor',
-        col = math.floor((columns - width) / 2), -- 两侧的宽度
-        row = float_conf.top_offset,
-        title = 'Trans',
-        title_pos = 'center',
-        style = 'minimal',
-        width = width,
-        height = height,
-        border = float_conf.border,
-        zindex = 50,
-    }
-end
-
-local get_cursor_opts = function(cursor_conf)
-    type_check {
-        cursor_conf = { cursor_conf, 'table' },
-    }
-    local opts = {
-        relative = 'cursor',
-        col = 2,
-        row = 2,
-        title = 'Trans',
-        title_pos = 'center',
-        style = 'minimal',
-        border = cursor_conf.border,
-        -- TODO keymap to convert style to Float
-        focusable = false,
-        zindex = 100,
-    }
-    if cursor_conf.style == 'fixed' then
-        opts.width = cursor_conf.width
-        opts.height = cursor_conf.height
-    elseif cursor_conf.style == 'relative' then
-        opts.width = (cursor_conf.width > 0 and conf.width < conf.max_width) and conf.width or conf.max_width
-        opts.height = (cursor_conf.height > 0 and conf.height < conf.max_height) and conf.height or conf.max_height
-    else
-        error('unknown style!')
-    end
-    return opts
-end
-
-M.float_opts = get_float_opts(conf.float)
-
-M.cursor_opts = get_cursor_opts(conf.cursor)
-
-return M
diff --git a/lua/Trans/core/init.lua b/lua/Trans/core/init.lua
index fd633ca..8a499bd 100644
--- a/lua/Trans/core/init.lua
+++ b/lua/Trans/core/init.lua
@@ -2,6 +2,6 @@ local M = {}
 
 M.process = require('Trans.core.process')
 M.query = require('Trans.core.query')
-M.show_win = require('Trans.core.show_win')
+-- M.show_win = require('Trans.core.show_win')
 
 return M
diff --git a/lua/Trans/core/show_win.lua b/lua/Trans/core/show_win.lua
deleted file mode 100644
index be06838..0000000
--- a/lua/Trans/core/show_win.lua
+++ /dev/null
@@ -1,54 +0,0 @@
-local type_check = require("Trans.util.debug").type_check
-
--- local win_opts = {
---     winhl = 'Normal:TransWinNormal, FloatBorder:TransWinBorder'
--- }
-
-local function caculate_format(height, width)
-    local col = math.floor((vim.o.lines - height - vim.o.cmdheight) / 2)
-    local row = math.floor((vim.o.columns - width) / 2)
-    return row, col
-end
-
-
-local function show_win(opts)
-    type_check {
-        opts = { opts, 'table' },
-        win = { opts.win, 'table' },
-        border = { opts.border, 'string' },
-        highlight = { opts.highlight, 'table', true },
-    }
-
-    local is_float = opts.style == 'float'
-    local win_opts = {
-        relative = opts.style == 'float' and 'editor' or 'cursor',
-        width = opts.width,
-        height = opts.height,
-        style = 'minimal',
-        border = opts.border,
-        title = 'Trans',
-        title_pos = 'center',
-        focusable = true,
-        zindex = 100,
-    }
-    if is_float then
-        win_opts.row, win_opts.col = caculate_format(win_opts.height, win_opts.width)
-    else
-        win_opts.row = 2
-        win_opts.col = 2
-    end
-
-    local winid = vim.api.nvim_open_win(bufnr, is_float, win_opts)
-
-    vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, opts.lines)
-
-    for line, l_hl in ipairs(opts.highlight) do
-        for i, hl in ipairs(l_hl) do
-            vim.api.nvim_buf_add_highlight(bufnr, line, hl.name, i, hl._start, hl._end)
-        end
-    end
-
-    return bufnr, winid
-end
-
-return show_win

From 01f5882b13d370675ed69046607fe51bfd772c2c Mon Sep 17 00:00:00 2001
From: JuanZoran <1430359574@qq.com>
Date: Tue, 10 Jan 2023 23:15:31 +0800
Subject: [PATCH 17/17] fix: add max_size support and definition need better
 format

---
 lua/.luarc.json                             |  3 +-
 lua/Trans/api/query.lua                     |  2 +-
 lua/Trans/component/content.lua             | 26 +++++----
 lua/Trans/component/highlight.lua           | 11 ----
 lua/Trans/component/offline/Definition.lua  | 65 ++++++++++++++++++++-
 lua/Trans/component/offline/Exchange.lua    | 42 ++++++++++++-
 lua/Trans/component/offline/Pos.lua         | 17 +++++-
 lua/Trans/component/offline/Tag.lua         | 13 ++---
 lua/Trans/component/offline/Translation.lua | 20 ++++++-
 lua/Trans/conf/default.lua                  | 17 +++---
 lua/Trans/conf/loader.lua                   | 13 ++---
 lua/Trans/core/process.lua                  | 58 +++++++++++++-----
 lua/Trans/core/query.lua                    |  2 +-
 lua/Trans/core/translate.lua                |  3 +-
 lua/Trans/setup.lua                         |  4 +-
 lua/Trans/util/debug.lua                    | 32 ----------
 16 files changed, 223 insertions(+), 105 deletions(-)
 delete mode 100644 lua/Trans/component/highlight.lua
 delete mode 100644 lua/Trans/util/debug.lua

diff --git a/lua/.luarc.json b/lua/.luarc.json
index cb3ed2f..8ae3698 100644
--- a/lua/.luarc.json
+++ b/lua/.luarc.json
@@ -8,5 +8,6 @@
         "vim",
         "user_conf",
         "default_conf"
-    ]
+    ],
+    "Lua.workspace.checkThirdParty": false
 }
\ No newline at end of file
diff --git a/lua/Trans/api/query.lua b/lua/Trans/api/query.lua
index d2645af..ad0014b 100644
--- a/lua/Trans/api/query.lua
+++ b/lua/Trans/api/query.lua
@@ -3,7 +3,7 @@ local _, db = pcall(require, 'sqlite.db')
 if not _ then
     error('Please check out sqlite.lua')
 end
-local type_check = require("Trans.util.debug").type_check
+local type_check = vim.validate
 
 -- INFO : init database
 local path = require("Trans.conf.loader").loaded_conf.base.db_path
diff --git a/lua/Trans/component/content.lua b/lua/Trans/component/content.lua
index 9960e2d..c04ee90 100644
--- a/lua/Trans/component/content.lua
+++ b/lua/Trans/component/content.lua
@@ -1,14 +1,20 @@
 local M = {}
-local type_check = require("Trans.util.debug").type_check
+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()
+
+function M:new(opts)
+    if opts then
+        self.opts = opts
+    end
+
     local content = {}
     setmetatable(content, self)
     return content
@@ -111,26 +117,26 @@ function M:data()
     return lines, highlights
 end
 
-function M:attach(bufnr, winid)
-    local height = vim.api.nvim_win_get_height(winid)
-    local width = vim.api.nvim_win_get_width(winid)
 
-    vim.api.nvim_win_set_height(winid, self.height)
+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(bufnr, 0, -1, false, lines)
+    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(bufnr, -1, hl.name, line - 1, hl._start, hl._end)
+            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(winid, self.height)
+        vim.api.nvim_win_set_height(self.opts.winid, self.height)
     end
 
     if self.width < width then
-        vim.api.nvim_win_set_width(winid, self.width)
+        vim.api.nvim_win_set_width(self.opts.winid, self.width)
     end
 end
 
diff --git a/lua/Trans/component/highlight.lua b/lua/Trans/component/highlight.lua
deleted file mode 100644
index 6732551..0000000
--- a/lua/Trans/component/highlight.lua
+++ /dev/null
@@ -1,11 +0,0 @@
-local M = {}
-local type_check = require("Trans.util.debug").type_check
-M.__index = M
-
-function M:new()
-    
-end
-
-
-return M
-
diff --git a/lua/Trans/component/offline/Definition.lua b/lua/Trans/component/offline/Definition.lua
index e557040..54d9f77 100644
--- a/lua/Trans/component/offline/Definition.lua
+++ b/lua/Trans/component/offline/Definition.lua
@@ -1,7 +1,68 @@
 local M = {}
 
-M.component = function (field)
-    -- TODO 
+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
+--]]
diff --git a/lua/Trans/component/offline/Exchange.lua b/lua/Trans/component/offline/Exchange.lua
index e557040..90cb93c 100644
--- a/lua/Trans/component/offline/Exchange.lua
+++ b/lua/Trans/component/offline/Exchange.lua
@@ -1,7 +1,45 @@
 local M = {}
 
-M.component = function (field)
-    -- TODO 
+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
diff --git a/lua/Trans/component/offline/Pos.lua b/lua/Trans/component/offline/Pos.lua
index e557040..7d52ae5 100644
--- a/lua/Trans/component/offline/Pos.lua
+++ b/lua/Trans/component/offline/Pos.lua
@@ -1,7 +1,20 @@
 local M = {}
 
-M.component = function (field)
-    -- TODO 
+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
diff --git a/lua/Trans/component/offline/Tag.lua b/lua/Trans/component/offline/Tag.lua
index a95080f..9ccf18e 100644
--- a/lua/Trans/component/offline/Tag.lua
+++ b/lua/Trans/component/offline/Tag.lua
@@ -25,17 +25,16 @@ M.component = function(field)
             needformat = true,
             highlight = 'TransTag',
             indent = 4,
+            emptyline = true,
         }
 
         for _tag in vim.gsplit(field.tag, ' ', true) do
-            if _tag ~= '' then
-                local tag = tag_map[_tag]
+            local tag = tag_map[_tag]
 
-                if tag then
-                    table.insert(tags, tag)
-                else
-                    error('add tag_map for [' .. _tag .. ']')
-                end
+            if tag then
+                table.insert(tags, tag)
+            else
+                error('add tag_map for [' .. _tag .. ']')
             end
         end
 
diff --git a/lua/Trans/component/offline/Translation.lua b/lua/Trans/component/offline/Translation.lua
index e557040..de61ffb 100644
--- a/lua/Trans/component/offline/Translation.lua
+++ b/lua/Trans/component/offline/Translation.lua
@@ -1,7 +1,23 @@
 local M = {}
 
-M.component = function (field)
-    -- TODO 
+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
diff --git a/lua/Trans/conf/default.lua b/lua/Trans/conf/default.lua
index 39fddc7..57a60b9 100644
--- a/lua/Trans/conf/default.lua
+++ b/lua/Trans/conf/default.lua
@@ -10,8 +10,8 @@ M.conf = {
         window = {
             cursor = {
                 border = 'rounded',
-                width = 40,
-                height = 20,
+                width = 50,
+                height = 50,
             },
             float = {
                 border = 'rounded',
@@ -33,10 +33,10 @@ M.conf = {
             'Pos',
             'Exchange',
             'Translation',
-            'Definition',
+            -- { 'Definition', max_size = 4 },
         },
         -- online = {
-        --     -- TODO 
+        --     -- TODO
         -- },
     },
     ui = {
@@ -46,7 +46,7 @@ M.conf = {
                 bold = true,
             },
             TransPhonetic = {
-                fg = '#8b949e',
+                link = 'Linenr'
             },
             TransRef = {
                 fg = '#75beff',
@@ -65,7 +65,8 @@ M.conf = {
                 link = 'TransWord',
             },
             TransDefinition = {
-                fg = '#bc8cff',
+                -- fg = '#bc8cff',
+                link = 'Moremsg',
             },
             TransCursorWin = {
                 link = 'Normal',
@@ -93,14 +94,14 @@ M.conf = {
         auto_close = true,
         engine = {
             -- TODO
-            'local',
+            'offline',
         }
     },
     -- map = {
     --     -- TODO
     -- },
     -- history = {
-    --     -- TOOD 
+    --     -- TOOD
     -- }
 
     -- TODO  add online translate engine
diff --git a/lua/Trans/conf/loader.lua b/lua/Trans/conf/loader.lua
index 3b3684f..8245116 100644
--- a/lua/Trans/conf/loader.lua
+++ b/lua/Trans/conf/loader.lua
@@ -45,16 +45,11 @@ M.load_conf = function(conf)
 
     pre_process()
     M.loaded_conf = vim.tbl_deep_extend('force', default_conf, user_conf)
-    local width = M.loaded_conf.style.window.float.width
-    local height = M.loaded_conf.style.window.float.height
+    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)
 
-    if width > 0 and width <= 1 then
-        M.loaded_conf.style.window.float.width = math.floor(width * vim.o.columns)
-    end
-
-    if height > 0 and height <= 1 then
-        M.loaded_conf.style.window.float.height = math.floor(height * (vim.o.lines - vim.o.cmdheight))
-    end
+    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
diff --git a/lua/Trans/core/process.lua b/lua/Trans/core/process.lua
index b94a105..aba65bf 100644
--- a/lua/Trans/core/process.lua
+++ b/lua/Trans/core/process.lua
@@ -1,4 +1,4 @@
-local type_check = require("Trans.util.debug").type_check
+local type_check = vim.validate
 
 -- NOTE :中文字符及占两个字节宽,但是在lua里是3个字节长度
 -- 为了解决中文字符在lua的长度和neovim显示不一致的问题
@@ -8,11 +8,15 @@ 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 + get_width(items[i][1]) + 4
+        tot_width = tot_width + #items[i][1] + 4
     end
 
 
@@ -23,22 +27,38 @@ local function format(win_width, items)
 
         -- 行内字符串按照宽度排序
         table.sort(items, function(a, b)
-            return get_width(a[1]) > get_width(b[1])
+            return #a[1] > #b[1]
         end)
 
         local cols = 1
-        win_width = win_width - get_width(items[1][1])
+        win_width = win_width - #items[1][1]
+
         while win_width > 0 and cols < size do
             cols = cols + 1
-            win_width = win_width - get_width(items[cols][1]) + 4
+            win_width = win_width - #items[cols][1] + 4
         end
-        cols = cols - 1
+        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 -- 当前操作的行号
@@ -48,6 +68,10 @@ local function format(win_width, items)
             }
 
             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
@@ -69,9 +93,8 @@ local function format(win_width, items)
         end
 
         return lines, true
-    else
-        return items
     end
+    return items
 end
 
 local function process(opts)
@@ -88,11 +111,16 @@ local function process(opts)
         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()
+        local content = require('Trans.component.content'):new(opts)
         for _, v in ipairs(opts.order) do
-            local component = require("Trans.component." .. 'offline' --[[ opts.engine ]] .. '.' .. v).component(opts.field)
+            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
 
@@ -105,23 +133,25 @@ local function process(opts)
                         else
                             content:insert(formatted_items)
                         end
-
                     else
                         content:insert(items)
                     end
 
+                    if items.emptyline then
+                        content:insert({ '' })
+                    end
                 end
             end
 
         end
 
-        content:attach(opts.bufnr, opts.winid)
-
+        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(
diff --git a/lua/Trans/core/query.lua b/lua/Trans/core/query.lua
index c973f44..5fdb0b0 100644
--- a/lua/Trans/core/query.lua
+++ b/lua/Trans/core/query.lua
@@ -1,4 +1,4 @@
-local type_check = require("Trans.util.debug").type_check
+local type_check = vim.validate
 local query = require("Trans.api").query
 
 local function get_select()
diff --git a/lua/Trans/core/translate.lua b/lua/Trans/core/translate.lua
index f336240..4ce2295 100644
--- a/lua/Trans/core/translate.lua
+++ b/lua/Trans/core/translate.lua
@@ -59,6 +59,7 @@ 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,
@@ -79,8 +80,8 @@ local function create_win(win)
         win_opts.col = 2
     end
 
-    local winid = vim.api.nvim_open_win(bufnr, is_float, win_opts)
 
+    local winid = vim.api.nvim_open_win(bufnr, is_float, win_opts)
     return bufnr, winid
 end
 
diff --git a/lua/Trans/setup.lua b/lua/Trans/setup.lua
index 2e0acb8..1fa8aef 100644
--- a/lua/Trans/setup.lua
+++ b/lua/Trans/setup.lua
@@ -5,14 +5,14 @@ end
 vim.api.nvim_create_user_command('Translate', function ()
     require("Trans").translate()
 end, {
-    desc = '翻译单词',
+    desc = '  单词翻译',
 })
 
 vim.api.nvim_create_user_command('TranslateInput', function ()
     require("Trans").translate {
         method = 'input',
     }
-end, {desc = '翻译单词'})
+end, {desc = '  搜索翻译'})
 
 -- TODO 
 -- vim.api.nvim_create_user_command('TranslateHistory', require("Trans.core").query_input, {
diff --git a/lua/Trans/util/debug.lua b/lua/Trans/util/debug.lua
deleted file mode 100644
index 3088acd..0000000
--- a/lua/Trans/util/debug.lua
+++ /dev/null
@@ -1,32 +0,0 @@
-local M = {}
-
--- INFO : get loaded debug conf
-local type_check = true
-
-M.type_check = function (types)
-    if type_check then
-        vim.validate(types)
-    end
-end
-
--- local function dedent(lines)
---     local ind_size = math.huge
---     for i, _ in ipairs(lines) do
---         local i1, i2 = lines[i]:find("^%s*[^%s]")
---         if i1 and i2 < ind_size then
---             ind_size = i2
---         end
---     end
---     for i, _ in ipairs(lines) do
---         lines[i] = lines[i]:sub(ind_size, -1)
---     end
--- end
---
--- function M.dedent(s)
---     local lst = vim.split(s, "\n")
---     dedent(lst)
---     return table.concat(lst, "\n")
--- end
-
-
-return M