mirror of
https://github.com/chenasraf/text-transform.nvim.git
synced 2026-05-17 17:48:04 +00:00
fix: range commands
This commit is contained in:
8
doc/tags
8
doc/tags
@@ -1,12 +1,9 @@
|
||||
TextTransform.config text-transform.txt /*TextTransform.config*
|
||||
TextTransform.enable() text-transform.txt /*TextTransform.enable()*
|
||||
TextTransform.get_visual_selection_details() text-transform.txt /*TextTransform.get_visual_selection_details()*
|
||||
TextTransform.init_commands() text-transform.txt /*TextTransform.init_commands()*
|
||||
TextTransform.replace_columns() text-transform.txt /*TextTransform.replace_columns()*
|
||||
TextTransform.replace_selection() text-transform.txt /*TextTransform.replace_selection()*
|
||||
TextTransform.replace_word() text-transform.txt /*TextTransform.replace_word()*
|
||||
TextTransform.restore_positions() text-transform.txt /*TextTransform.restore_positions()*
|
||||
TextTransform.save_positions() text-transform.txt /*TextTransform.save_positions()*
|
||||
TextTransform.setup() text-transform.txt /*TextTransform.setup()*
|
||||
TextTransform.to_camel_case() text-transform.txt /*TextTransform.to_camel_case()*
|
||||
TextTransform.to_const_case() text-transform.txt /*TextTransform.to_const_case()*
|
||||
@@ -16,10 +13,13 @@ TextTransform.to_pascal_case() text-transform.txt /*TextTransform.to_pascal_case
|
||||
TextTransform.to_snake_case() text-transform.txt /*TextTransform.to_snake_case()*
|
||||
TextTransform.to_title_case() text-transform.txt /*TextTransform.to_title_case()*
|
||||
TextTransform.to_words() text-transform.txt /*TextTransform.to_words()*
|
||||
TextTransform.toggle() text-transform.txt /*TextTransform.toggle()*
|
||||
TextTransform.transform_words() text-transform.txt /*TextTransform.transform_words()*
|
||||
find_word_boundaries() text-transform.txt /*find_word_boundaries()*
|
||||
init() text-transform.txt /*init()*
|
||||
state.enable() text-transform.txt /*state.enable()*
|
||||
state.restore_positions() text-transform.txt /*state.restore_positions()*
|
||||
state.save_positions() text-transform.txt /*state.save_positions()*
|
||||
state.toggle() text-transform.txt /*state.toggle()*
|
||||
telescope.telescope_popup() text-transform.txt /*telescope.telescope_popup()*
|
||||
utils.dump() text-transform.txt /*utils.dump()*
|
||||
utils.merge() text-transform.txt /*utils.merge()*
|
||||
|
||||
@@ -117,26 +117,26 @@ the full information around the selection logic.
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.toggle()*
|
||||
`TextTransform.toggle`()
|
||||
*state.toggle()*
|
||||
`state.toggle`()
|
||||
Toggle the plugin by calling the `enable`/`disable` methods respectively.
|
||||
@private
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.enable()*
|
||||
`TextTransform.enable`()
|
||||
*state.enable()*
|
||||
`state.enable`()
|
||||
Enables the plugin
|
||||
@private
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.save_positions()*
|
||||
`TextTransform.save_positions`()
|
||||
*state.save_positions()*
|
||||
`state.save_positions`()
|
||||
Save the current cursor position, mode, and visual selection ranges
|
||||
@private
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.restore_positions()*
|
||||
`TextTransform.restore_positions`({state})
|
||||
*state.restore_positions()*
|
||||
`state.restore_positions`({new_state})
|
||||
Restore the cursor position, mode, and visual selection ranges saved using `save_position()`,
|
||||
or a given modified state, if passed as the first argument
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
-- local D = require("text-transform.util.debug")
|
||||
local state = require("text-transform.state")
|
||||
local replacers = require("text-transform.replacers")
|
||||
local popup = require("text-transform.popup")
|
||||
@@ -16,22 +17,24 @@ function TextTransform.init_commands()
|
||||
TtTitle = "title_case",
|
||||
}
|
||||
|
||||
local cmdopts = { range = true, force = true }
|
||||
|
||||
for cmd, transformer_name in pairs(map) do
|
||||
vim.api.nvim_create_user_command(cmd, function()
|
||||
state.save_positions()
|
||||
replacers.replace_selection(transformer_name)
|
||||
end, {})
|
||||
end, cmdopts)
|
||||
end
|
||||
|
||||
-- specific popups
|
||||
vim.api.nvim_create_user_command("TtTelescope", function()
|
||||
local telescope = require("text-transform.telescope")
|
||||
telescope.telescope_popup()
|
||||
end, {})
|
||||
end, cmdopts)
|
||||
vim.api.nvim_create_user_command("TtSelect", function()
|
||||
local select = require("text-transform.select")
|
||||
select.select_popup()
|
||||
end, {})
|
||||
end, cmdopts)
|
||||
|
||||
-- auto popup by config
|
||||
vim.api.nvim_create_user_command("TextTransform", popup.show_popup, {})
|
||||
|
||||
@@ -19,14 +19,18 @@ local function find_word_boundaries(line, start_col)
|
||||
local word_end_col = vim.fn.match(line_text:sub(word_start_col), non_word_pat)
|
||||
+ word_start_col
|
||||
- 1
|
||||
D.log("replacers", "Found word boundaries: %s", vim.inspect({ word_start_col, word_end_col }))
|
||||
D.log("replacers", "Word text: %s", line_text:sub(word_start_col, word_end_col))
|
||||
D.log("replacers", "Line text: %s", line_text)
|
||||
D.log(
|
||||
"find_word_boundaries",
|
||||
"Found word boundaries: %s",
|
||||
vim.inspect({ word_start_col, word_end_col })
|
||||
)
|
||||
D.log("find_word_boundaries", "Word text: %s", line_text:sub(word_start_col, word_end_col))
|
||||
D.log("find_word_boundaries", "Line text: %s", line_text)
|
||||
return word_start_col, word_end_col
|
||||
end
|
||||
|
||||
function TextTransform.replace_range(start_line, start_col, end_line, end_col, transform_name)
|
||||
D.log("replacers", "Replacing range with %s", transform_name)
|
||||
D.log("replace_range", "Replacing range with %s", transform_name)
|
||||
local transform = t["to_" .. transform_name]
|
||||
local lines = vim.fn.getline(start_line, end_line) --- @type any
|
||||
local transformed = {}
|
||||
@@ -58,7 +62,7 @@ end
|
||||
--- @param transform_name string The transformer name
|
||||
--- @param position table|nil A table containing the position of the word to replace
|
||||
function TextTransform.replace_word(transform_name, position)
|
||||
D.log("replacers", "Replacing word with %s", transform_name)
|
||||
D.log("replace_word", "Replacing word with %s", transform_name)
|
||||
local word, line, col, start_col, end_col
|
||||
if not position then
|
||||
word = vim.fn.expand("<cword>")
|
||||
@@ -67,11 +71,11 @@ function TextTransform.replace_word(transform_name, position)
|
||||
start_col, end_col = find_word_boundaries(line, col)
|
||||
word = vim.fn.getline(line):sub(start_col, end_col)
|
||||
end
|
||||
D.log("replacers", "Found word %s", word)
|
||||
D.log("replacers", "Using transformer %s", transform_name)
|
||||
D.log("replace_word", "Found word %s", word)
|
||||
D.log("replace_word", "Using transformer %s", transform_name)
|
||||
local transformer = t["to_" .. transform_name]
|
||||
local transformed = transformer(word)
|
||||
D.log("replacers", "New value %s", transformed)
|
||||
D.log("replace_word", "New value %s", transformed)
|
||||
if not position then
|
||||
vim.cmd("normal ciw" .. transformed)
|
||||
else
|
||||
@@ -83,7 +87,7 @@ end
|
||||
--- Assumes that the each selection is 1 character and operates on the whole word under each cursor.
|
||||
function TextTransform.replace_columns(transform_name)
|
||||
local selections = TextTransform.get_visual_selection_details()
|
||||
D.log("replacers", "Replacing columns with %s", transform_name)
|
||||
D.log("replace_columns", "Replacing columns with %s", transform_name)
|
||||
for _, sel in ipairs(selections) do
|
||||
TextTransform.replace_word(transform_name, { 0, sel.start_line, sel.start_col, 0 })
|
||||
end
|
||||
@@ -95,20 +99,22 @@ end
|
||||
---
|
||||
--- @param transform_name string The transformer name
|
||||
function TextTransform.replace_selection(transform_name)
|
||||
D.log("replacers", "Replacing selection with %s", transform_name)
|
||||
D.log("replace_selection", "Replacing selection with %s", transform_name)
|
||||
-- determine if cursor is a 1-width column across multiple lines or a normal selection
|
||||
-- local start_line, start_col, end_line, end_col = unpack(vim.fn.getpos("'<"))
|
||||
local selections = TextTransform.get_visual_selection_details()
|
||||
|
||||
D.log("replacers", "Selections: %s", utils.dump(selections))
|
||||
D.log("replace_selection", "Selections: %s", utils.dump(selections))
|
||||
local is_multiline = #selections > 1
|
||||
local is_column = is_multiline and selections[1].start_col == selections[#selections].end_col
|
||||
local is_single_cursor = not is_multiline
|
||||
and not is_column
|
||||
and selections
|
||||
and selections[1]
|
||||
and selections[1].start_col == selections[1].end_col
|
||||
|
||||
D.log(
|
||||
"replacers",
|
||||
"replace_selection",
|
||||
"is_multiline: %s, is_column: %s, is_word: %s",
|
||||
is_multiline,
|
||||
is_column,
|
||||
@@ -139,19 +145,31 @@ end
|
||||
--- the full information around the selection logic.
|
||||
function TextTransform.get_visual_selection_details()
|
||||
if not state.positions then
|
||||
D.log("replacers", "No positions saved")
|
||||
D.log("get_visual_selection_details", "No positions saved")
|
||||
return {}
|
||||
end
|
||||
D.log(
|
||||
"replacers",
|
||||
"get_visual_selection_details",
|
||||
"Getting visual selection details - mode: %s, is_visual: %s, is_block: %s",
|
||||
state.positions.mode,
|
||||
utils.is_visual_mode(),
|
||||
utils.is_block_visual_mode()
|
||||
)
|
||||
|
||||
-- Get the start and end positions of the selection
|
||||
local start_pos = state.positions.visual_start
|
||||
local end_pos = state.positions.visual_end
|
||||
local start_line, start_col = start_pos[2], start_pos[3]
|
||||
local end_line, end_col = end_pos[2], end_pos[3]
|
||||
|
||||
-- Check if currently in visual mode; if not, return the cursor position
|
||||
if not utils.is_visual_mode() and not utils.is_block_visual_mode() then
|
||||
if
|
||||
not utils.is_visual_mode()
|
||||
and not utils.is_block_visual_mode()
|
||||
and not state.has_range(start_pos, end_pos)
|
||||
then
|
||||
local pos = state.positions.pos
|
||||
D.log("get_visual_selection_details", "Returning single cursor position")
|
||||
return {
|
||||
{
|
||||
start_line = pos[2],
|
||||
@@ -162,12 +180,6 @@ function TextTransform.get_visual_selection_details()
|
||||
}
|
||||
end
|
||||
|
||||
-- Get the start and end positions of the selection
|
||||
local start_pos = state.positions.visual_start
|
||||
local end_pos = state.positions.visual_end
|
||||
local start_line, start_col = start_pos[2], start_pos[3]
|
||||
local end_line, end_col = end_pos[2], end_pos[3]
|
||||
|
||||
-- Swap if selection is made upwards or backwards
|
||||
if start_line > end_line or (start_line == end_line and start_col > end_col) then
|
||||
start_line, end_line = end_line, start_line
|
||||
@@ -175,7 +187,7 @@ function TextTransform.get_visual_selection_details()
|
||||
end
|
||||
|
||||
-- If it's block visual mode, return table for each row
|
||||
if utils.is_block_visual_mode() then
|
||||
if utils.is_block_visual_mode() or state.has_range(start_pos, end_pos) then
|
||||
local block_selection = {}
|
||||
for line = start_line, end_line do
|
||||
if start_col == end_col then
|
||||
@@ -189,9 +201,15 @@ function TextTransform.get_visual_selection_details()
|
||||
end_col = start_col,
|
||||
})
|
||||
end
|
||||
D.log(
|
||||
"get_visual_selection_details",
|
||||
"Returning block selection: %s",
|
||||
utils.dump(block_selection)
|
||||
)
|
||||
return block_selection
|
||||
else
|
||||
-- Normal visual mode, return single table entry
|
||||
D.log("get_visual_selection_details", "Returning normal selection")
|
||||
return {
|
||||
{
|
||||
start_line = start_line,
|
||||
|
||||
@@ -8,7 +8,7 @@ local function ensure_config()
|
||||
end
|
||||
|
||||
-- methods
|
||||
local TextTransform = {
|
||||
local state = {
|
||||
-- Boolean determining if the plugin is enabled or not.
|
||||
enabled = false,
|
||||
-- A table containing cursor position and visual selection details,
|
||||
@@ -18,40 +18,40 @@ local TextTransform = {
|
||||
|
||||
--- Toggle the plugin by calling the `enable`/`disable` methods respectively.
|
||||
--- @private
|
||||
function TextTransform.toggle()
|
||||
if TextTransform.enabled then
|
||||
return TextTransform.disable()
|
||||
function state.toggle()
|
||||
if state.enabled then
|
||||
return state.disable()
|
||||
end
|
||||
|
||||
return TextTransform.enable()
|
||||
return state.enable()
|
||||
end
|
||||
|
||||
--- Enables the plugin
|
||||
--- @private
|
||||
function TextTransform.enable()
|
||||
function state.enable()
|
||||
ensure_config()
|
||||
|
||||
if TextTransform.enabled then
|
||||
return TextTransform
|
||||
if state.enabled then
|
||||
return state
|
||||
end
|
||||
|
||||
TextTransform.enabled = true
|
||||
return TextTransform
|
||||
state.enabled = true
|
||||
return state
|
||||
end
|
||||
|
||||
---Disables the plugin and reset the internal state.
|
||||
---@private
|
||||
function TextTransform.disable()
|
||||
function state.disable()
|
||||
ensure_config()
|
||||
|
||||
if not TextTransform.enabled then
|
||||
return TextTransform
|
||||
if not state.enabled then
|
||||
return state
|
||||
end
|
||||
|
||||
-- reset the state
|
||||
TextTransform.enabled = false
|
||||
TextTransform.positions = nil
|
||||
return TextTransform
|
||||
state.enabled = false
|
||||
state.positions = nil
|
||||
return state
|
||||
end
|
||||
|
||||
local function get_mode_type(mode)
|
||||
@@ -64,6 +64,10 @@ local function get_mode_type(mode)
|
||||
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
|
||||
@@ -78,7 +82,7 @@ end
|
||||
|
||||
--- Save the current cursor position, mode, and visual selection ranges
|
||||
--- @private
|
||||
function TextTransform.save_positions()
|
||||
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)
|
||||
@@ -92,8 +96,13 @@ function TextTransform.save_positions()
|
||||
D.log("save_positions", "Saved mode %s, cursor %s", mode, vim.inspect(pos))
|
||||
|
||||
if mode == "visual" or mode == "line" or mode == "block" then
|
||||
if mode == "block" then -- for block visual mode
|
||||
D.log("save_positions", "Visual mode is block, %s", vim.inspect({ visual_start, visual_end }))
|
||||
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")
|
||||
@@ -106,7 +115,7 @@ function TextTransform.save_positions()
|
||||
)
|
||||
end
|
||||
|
||||
local state = {
|
||||
local positions = {
|
||||
buf = buf,
|
||||
mode = mode,
|
||||
pos = pos,
|
||||
@@ -114,32 +123,37 @@ function TextTransform.save_positions()
|
||||
visual_end = visual_end,
|
||||
}
|
||||
|
||||
D.log("save_positions", "State: %s", vim.inspect(state))
|
||||
TextTransform.positions = state
|
||||
return state
|
||||
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 TextTransform.restore_positions(state)
|
||||
state = state or TextTransform.positions
|
||||
vim.api.nvim_set_current_buf(state.buf)
|
||||
vim.fn.setpos(".", state.pos)
|
||||
D.log("restore_positions", "Restored mode %s, cursor %s", state.mode, vim.inspect(state.pos))
|
||||
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
|
||||
(state.mode == "visual" or state.mode == "block")
|
||||
and state.visual_start
|
||||
and state.visual_end
|
||||
(new_state.mode == "visual" or new_state.mode == "block")
|
||||
and new_state.visual_start
|
||||
and new_state.visual_end
|
||||
then
|
||||
vim.fn.setpos("'<", state.visual_start)
|
||||
vim.fn.setpos("'>", state.visual_end)
|
||||
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"]], state.mode, command)
|
||||
D.log("restore_positions", [[Restored visual mode %s using "%s"]], new_state.mode, command)
|
||||
end
|
||||
TextTransform.positions = nil
|
||||
new_state.positions = nil
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
return state
|
||||
|
||||
@@ -47,12 +47,12 @@ function TextTransform.to_words(string)
|
||||
-- Append current character to the current word
|
||||
word = word .. char
|
||||
end
|
||||
D.log("transformers", "i %d char %s word %s words %s", i, char, word, utils.dump(words))
|
||||
-- D.log("to_words", "i %d char %s word %s words %s", i, char, word, utils.dump(words))
|
||||
end
|
||||
if word ~= "" then
|
||||
table.insert(words, word:lower())
|
||||
end
|
||||
D.log("transformers", "words %s", vim.inspect(words))
|
||||
D.log("to_words", "words %s", vim.inspect(words))
|
||||
return words
|
||||
end
|
||||
|
||||
@@ -75,7 +75,7 @@ function TextTransform.transform_words(words, with_word_cb, separator)
|
||||
new_word = separator .. new_word
|
||||
end
|
||||
out = out .. new_word
|
||||
D.log("transformers", "word %s (%d) new_word %s out %s", word, i, new_word, out)
|
||||
D.log("transform_words", "word %s (%d) new_word %s out %s", word, i, new_word, out)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
@@ -26,10 +26,10 @@ function D.log(scope, str, ...)
|
||||
|
||||
print(
|
||||
string.format(
|
||||
"[text-transform:%s %s in %s] > %s",
|
||||
"%s [text-transform:%s in %s] > %s",
|
||||
os.date("%H:%M:%S"),
|
||||
line,
|
||||
scope,
|
||||
line,
|
||||
string.format(str, ...)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -30,4 +30,8 @@ function utils.is_visual_mode()
|
||||
-- return vim.fn.mode() == 'v'
|
||||
end
|
||||
|
||||
function utils.has_range(visual_start, visual_end)
|
||||
return visual_start and visual_end and visual_start[2] ~= visual_end[2]
|
||||
end
|
||||
|
||||
return utils
|
||||
|
||||
Reference in New Issue
Block a user