mirror of
https://github.com/chenasraf/text-transform.nvim.git
synced 2026-05-17 17:48:04 +00:00
160 lines
4.2 KiB
Lua
160 lines
4.2 KiB
Lua
local D = require("text-transform.util.debug")
|
|
|
|
local function ensure_config()
|
|
-- when the config is not set to the global object, we set it
|
|
if _G.TextTransform.config == nil then
|
|
_G.TextTransform.config = require("text-transform.config").config
|
|
end
|
|
end
|
|
|
|
-- methods
|
|
local state = {
|
|
-- Boolean determining if the plugin is enabled or not.
|
|
enabled = false,
|
|
-- A table containing cursor position and visual selection details,
|
|
-- saved using `save_position()` and can be restored using `restore_positions()`
|
|
positions = nil,
|
|
}
|
|
|
|
--- Toggle the plugin by calling the `enable`/`disable` methods respectively.
|
|
--- @private
|
|
function state.toggle()
|
|
if state.enabled then
|
|
return state.disable()
|
|
end
|
|
|
|
return state.enable()
|
|
end
|
|
|
|
--- Enables the plugin
|
|
--- @private
|
|
function state.enable()
|
|
ensure_config()
|
|
|
|
if state.enabled then
|
|
return state
|
|
end
|
|
|
|
state.enabled = true
|
|
return state
|
|
end
|
|
|
|
---Disables the plugin and reset the internal state.
|
|
---@private
|
|
function state.disable()
|
|
ensure_config()
|
|
|
|
if not state.enabled then
|
|
return state
|
|
end
|
|
|
|
-- reset the state
|
|
state.enabled = false
|
|
state.positions = nil
|
|
return state
|
|
end
|
|
|
|
local function get_mode_type(mode)
|
|
-- classify mode as either visual, line, block or normal
|
|
local mode_map = {
|
|
["v"] = "visual",
|
|
["V"] = "line",
|
|
["\22"] = "block",
|
|
}
|
|
return mode_map[mode] or "normal"
|
|
end
|
|
|
|
function state.has_range(visual_start, visual_end)
|
|
return visual_start and visual_end and visual_start[2] ~= visual_end[2]
|
|
end
|
|
|
|
local function capture_part(start_sel, end_sel, return_type)
|
|
local l, sel
|
|
if return_type == "start" then
|
|
l = math.min(start_sel[2], end_sel[2])
|
|
sel = start_sel
|
|
else
|
|
l = math.max(start_sel[2], end_sel[2])
|
|
sel = end_sel
|
|
end
|
|
return { sel[1], l, sel[3], sel[4] }
|
|
end
|
|
|
|
--- Save the current cursor position, mode, and visual selection ranges
|
|
--- @private
|
|
function state.save_positions()
|
|
local buf = vim.api.nvim_get_current_buf()
|
|
local mode_info = vim.api.nvim_get_mode()
|
|
local mode = get_mode_type(mode_info.mode)
|
|
local pos = vim.fn.getcurpos()
|
|
-- leave mode, required to get the positions - they only register on mode leave
|
|
-- in case of visual mode
|
|
local esc = vim.api.nvim_replace_termcodes("<esc>", true, false, true)
|
|
vim.api.nvim_feedkeys(esc, "x", true)
|
|
local visual_start = vim.fn.getpos("'<")
|
|
local visual_end = vim.fn.getpos("'>")
|
|
D.log("save_positions", "Saved mode %s, cursor %s", mode, vim.inspect(pos))
|
|
|
|
if mode == "visual" or mode == "line" or mode == "block" then
|
|
if state.has_range(visual_start, visual_end) then -- for ranges
|
|
D.log(
|
|
"save_positions",
|
|
"Visual range, mode is %s, %s",
|
|
mode,
|
|
vim.inspect({ visual_start, visual_end })
|
|
)
|
|
-- Adjust the positions to correctly capture the entire block
|
|
visual_start = capture_part(visual_start, visual_end, "start")
|
|
visual_end = capture_part(visual_start, visual_end, "end")
|
|
end
|
|
D.log(
|
|
"state",
|
|
"Saved visual mode %s, cursor %s",
|
|
mode,
|
|
vim.inspect({ visual_start, visual_end })
|
|
)
|
|
end
|
|
|
|
local positions = {
|
|
buf = buf,
|
|
mode = mode,
|
|
pos = pos,
|
|
visual_start = visual_start,
|
|
visual_end = visual_end,
|
|
}
|
|
|
|
D.log("save_positions", "State: %s", vim.inspect(positions))
|
|
state.positions = positions
|
|
return positions
|
|
end
|
|
|
|
--- Restore the cursor position, mode, and visual selection ranges saved using `save_position()`,
|
|
--- or a given modified state, if passed as the first argument
|
|
function state.restore_positions(new_state)
|
|
new_state = new_state or new_state.positions
|
|
vim.api.nvim_set_current_buf(new_state.buf)
|
|
vim.fn.setpos(".", new_state.pos)
|
|
D.log(
|
|
"restore_positions",
|
|
"Restored mode %s, cursor %s",
|
|
new_state.mode,
|
|
vim.inspect(new_state.pos)
|
|
)
|
|
|
|
-- Attempt to restore visual mode accurately
|
|
if
|
|
(new_state.mode == "visual" or new_state.mode == "block")
|
|
and new_state.visual_start
|
|
and new_state.visual_end
|
|
then
|
|
vim.fn.setpos("'<", new_state.visual_start)
|
|
vim.fn.setpos("'>", new_state.visual_end)
|
|
local command = "normal! gv"
|
|
vim.cmd(command)
|
|
D.log("restore_positions", [[Restored visual mode %s using "%s"]], new_state.mode, command)
|
|
end
|
|
new_state.positions = nil
|
|
end
|
|
|
|
return state
|