2023-05-15 12:43:42 +08:00

253 lines
6.6 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local fn, api = vim.fn, vim.api
---@class TransUtil
local M = require 'Trans'.metatable 'util'
---Get the range of visual modes
---@return table
function M.get_range()
local _start = fn.getpos 'v'
local _end = fn.getpos '.'
local s_row, e_row = math.min(_start[2], _end[2]), math.max(_start[2], _end[2])
local s_col, e_col = math.min(_start[3], _end[3]), math.max(_start[3], _end[3])
return { s_row, e_row, s_col, e_col }
end
---Get selected text
---@return string
function M.get_select()
local s_row, e_row, s_col, e_col = unpack(M.get_range())
---@type string
---@diagnostic disable-next-line: assign-type-mismatch
local line = fn.getline(e_row)
local uidx = vim.str_utfindex(line, math.min(#line, e_col))
---@diagnostic disable-next-line: param-type-mismatch
e_col = vim.str_byteindex(line, uidx)
if s_row == e_row then
return line:sub(s_col, e_col)
else
local lines = fn.getline(s_row, e_row)
local e = #lines
lines[1] = lines[1]:sub(s_col)
lines[e] = line:sub(1, e_col)
return table.concat(lines, ' ')
end
end
---Get selected text
---@return string
function M.get_lines()
local s_row, e_row = unpack(M.get_range())
if s_row == e_row then
return fn.getline(s_row)
else
local lines = fn.getline(s_row, e_row)
return table.concat(lines, " ")
end
end
---Get selected text
---@return string
function M.get_block()
local s_row, e_row, s_col, e_col = unpack(M.get_range())
---@type string
---@diagnostic disable-next-line: assign-type-mismatch
local line = fn.getline(e_row)
local uidx = vim.str_utfindex(line, math.min(#line, e_col))
---@diagnostic disable-next-line: param-type-mismatch
e_col = vim.str_byteindex(line, uidx)
if s_row == e_row then
return line:sub(s_col, e_col)
else
local lines = fn.getline(s_row, e_row)
for col, l in pairs(lines) do
lines[col] = l:sub(s_col,e_col)
end
return table.concat(lines, " ")
end
end
---Get Text which need to be translated
---@param mode string
---@return string
function M.get_str(mode)
return ({
n = function()
return fn.expand '<cword>'
end,
v = function()
api.nvim_input '<Esc>'
return M.get_select()
end,
i = function()
return fn.input '需要翻译的字符串: '
end,
V = function()
api.nvim_input '<Esc>'
return M.get_lines()
end,
[''] = function()
api.nvim_input '<Esc>'
return M.get_block()
end,
})[mode]():match '^%s*(.-)%s*$'
end
---Puase coroutine for {ms} milliseconds
---@param ms integer
function M.pause(ms)
assert(ms)
local co = coroutine.running()
vim.defer_fn(function()
coroutine.resume(co)
end, ms)
coroutine.yield()
end
---Detect whether the string is English
---@param str string
---@return boolean
function M.is_english(str)
local char = { str:byte(1, -1) }
for i = 1, #str do
if char[i] > 128 then
return false
end
end
return true
end
---Calculates the height of the text to be displayed
---@param lines string[] text to be displayed
---@param width integer width of the window
---@return integer height display height
function M.display_height(lines, width)
local height = 0
for _, line in ipairs(lines) do
height = height + math.max(1, (math.ceil(line:width() / width)))
end
return height
end
---Calculates the width of the text to be displayed
---@param lines string[] text to be displayed
---@return integer width display width
function M.display_width(lines)
local width = 0
for _, line in ipairs(lines) do
width = math.max(line:width(), width)
end
return width
end
---Center node utility function
---@param node string -- TODO :Node
---@param win_width integer window width
---@return string
function M.center(node, win_width)
if type(node) == 'string' then
local space = math.max(0, math.floor((win_width - node:width()) / 2))
return string.rep(' ', space) .. node
end
local str = node[1]
local space = math.max(0, math.floor((win_width - str:width()) / 2))
node[1] = string.rep(' ', space) .. str
return node
end
---Execute function in main loop
---@param func function function to be executed
function M.main_loop(func)
local co = coroutine.running()
vim.defer_fn(function()
func()
coroutine.resume(co)
end, 0)
coroutine.yield()
end
---Split text into paragraphs
---@param lines string[] text to be split
---@return string[][] paragraphs
function M.split_to_paragraphs(lines, opts)
--- TODO :More options and better algorithm to detect paragraphs
opts = opts or {}
local paragraphs = {}
local paragraph = {}
for _, line in ipairs(lines) do
if line == '' then
paragraphs[#paragraphs + 1] = paragraph
paragraph = {}
else
paragraph[#paragraph + 1] = line
end
end
return paragraphs
end
---Get visible lines in the window or current window
---@param opts { winid: integer, height: integer }?
---@return string[]
function M.visible_lines(opts)
opts = opts or {}
-- TODO : Use getpos('w0') and getpos('w$') to get the visible lines
-- INFO : don't calculate the height of statusline and cmdheight or winbar?
local winid = opts.winid or 0
local win_height = opts.height or api.nvim_win_get_height(winid)
local current_line = api.nvim_win_get_cursor(winid)[1]
local current_relative_line = vim.fn.winline()
local _start = current_line - current_relative_line
local _end = _start + win_height - vim.o.cmdheight --[[ - 1 -- maybe 1 for statusline?? ]]
return api.nvim_buf_get_lines(0, _start, _end, false)
end
---Detect whether the string is a word
---@param str string
---@return boolean
function M.is_word(str)
return str:find '%W' == nil
end
---@param list any[]
---@param step table
---@return any[]
function M.list_concat(list, step)
local size = #list
local ret = { list[1] }
if size <= 1 then return ret end
for i = 2, size do
ret[i * 2 - 2] = step
ret[i * 2 - 1] = list[i]
end
-- FIXME : Use deepcopy step?
return ret
end
---Get the field of the list
---@param list any[]
---@param field any
---@return any[]
function M.list_fields(list, field)
local ret = {}
for i, v in ipairs(list) do
ret[i] = v[field]
end
return ret
end
---@class Trans
---@field util TransUtil
return M