Skip to content
Draft

wip #35

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions lua/ts-node-action/actions/toggle_multiline.lua
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
local helpers = require("ts-node-action.helpers")

local function collapse_child_nodes(padding)
padding = padding or {}
---@param padding table Used to specify string formatting for unnamed nodes
---@param uncollapsible table Used to specify "base" types that shouldn't be collapsed further.
---@return function
local function collapse_child_nodes(padding, uncollapsible)
local function can_be_collapsed(child)
return child:named_child_count() > 0 and not uncollapsible[child:type()]
end

local function collapse(node)
return function(node)
local replacement = {}
local child_text
local context

for child, _ in node:iter_children() do
if child:named_child_count() > 0 then
child_text = collapse(child)
if child_text == nil then
return
end
if can_be_collapsed(child) then
local child_text = collapse_child_nodes(padding, uncollapsible)(child)
if not child_text then return end -- We found a comment, abort

table.insert(replacement, child_text)
context = nil
elseif child:type() == "comment" then
elseif child:type() == "comment" then -- TODO: use child:extra() when that API gets merged into stable
return
else
context = helpers.padded_node_text(child, padding, context)
table.insert(replacement, context)
table.insert(replacement, helpers.padded_node_text(child, padding))
end
end

return table.concat(vim.tbl_flatten(replacement))
end

return collapse
end

---@param node TSNode
---@return table
local function expand_child_nodes(node)
local replacement = {}

Expand All @@ -50,13 +50,17 @@ local function expand_child_nodes(node)
return replacement
end

return function(padding)
padding = padding or {}
---@param padding table
---@param uncollapsible table
---@return table
return function(padding, uncollapsible)
padding = padding or {}
uncollapsible = uncollapsible or {}

local function action(node)
local fn
if helpers.node_is_multiline(node) then
fn = collapse_child_nodes(padding)
fn = collapse_child_nodes(padding, uncollapsible)
else
fn = expand_child_nodes
end
Expand Down
9 changes: 5 additions & 4 deletions lua/ts-node-action/filetypes/lua.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,21 @@ local quote_override = {

local function toggle_function(node)
local struct = helpers.destructure_node(node)
if struct.body:match("\n") then
if type(struct.body) == "table" then
return
end

if helpers.node_is_multiline(node) then
return "function" .. struct.parameters .. " " .. struct.body .. " end"
local body = struct.body and (struct.body .. " ") or ""
return "function" .. struct.parameters .. " " .. body .. "end"
else
return { "function" .. struct.parameters, struct.body, "end" }, { format = true, cursor = {} }
return { "function" .. struct.parameters, struct.body or "", "end" }, { format = true, cursor = {} }
end
end

local function toggle_named_function(node)
local struct = helpers.destructure_node(node)
if struct.body:match("\n") then
if type(struct.body) == "table" then
return
end

Expand Down
74 changes: 36 additions & 38 deletions lua/ts-node-action/filetypes/python.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local actions = require("ts-node-action.actions")
-- a normal case. For unary, we don't want any padding, and generally (always?)
-- it is preceded by a named node. When padding, we see these as
-- prev_text=nil, so we can use that to detect the unary case with a special
-- key "nil", to represent it.
-- key "prev_nil", to represent it.
local padding = {
[","] = "%s ",
[":"] = "%s ",
Expand All @@ -28,16 +28,16 @@ local padding = {
["and"] = " %s ",
["or"] = " %s ",
["is"] = " %s ",
["not"] = { [""] = " %s ", ["is"] = "%s " },
["in"] = { [""] = " %s ", ["not"] = "%s " },
["not"] = { " %s ", ["is"] = "%s " },
["in"] = { " %s ", ["not"] = "%s " },
["=="] = " %s ",
["!="] = " %s ",
[">="] = " %s ",
["<="] = " %s ",
[">"] = " %s ",
["<"] = " %s ",
["+"] = " %s ",
["-"] = { [""] = " %s ", ["nil"] = "%s", },
["-"] = { " %s ", ["prev_nil"] = "%s", },
["*"] = " %s ",
["/"] = " %s ",
["//"] = " %s ",
Expand All @@ -58,10 +58,7 @@ local boolean_override = {
--- @param node TSNode
local function node_trim_whitespace(node)
local start_row, _, end_row, _ = node:range()
vim.cmd(
"silent! keeppatterns " .. (start_row + 1) .. "," .. (end_row + 1) ..
"s/\\s\\+$//g"
)
vim.cmd("silent! keeppatterns " .. (start_row + 1) .. "," .. (end_row + 1) .. "s/\\s\\+$//g")
end

-- When inlined, these nodes must be parenthesized to avoid changing the
Expand All @@ -82,10 +79,10 @@ local node_types_to_parenthesize = {
}

local function parenthesize_if_needed(node, text)
if node_types_to_parenthesize[node:type()] and
text:sub(1, 1) ~= "(" then
if node_types_to_parenthesize[node:type()] and text:sub(1, 1) ~= "(" then
return "(" .. text .. ")"
end

return text
end

Expand All @@ -104,8 +101,10 @@ local function collapse_child_nodes(padding_override)
if not helpers.node_is_multiline(node) then
return helpers.node_text(node)
end

local tbl = actions.toggle_multiline(padding_override)
local replacement = tbl[1][1](node)

return replacement
end

Expand All @@ -123,10 +122,10 @@ end
--- @param node TSNode
--- @return string|nil, string|nil, string
local function node_text_lhs_rhs(node, padding_override)
local lhs = nil
local rhs = nil
local type = node:type()
local child = node:named_child(0)
local lhs = nil
local rhs = nil
local type = node:type()
local child = node:named_child(0)
local collapse = collapse_child_nodes(padding_override)

if type == "return_statement" then
Expand All @@ -147,10 +146,10 @@ local function node_text_lhs_rhs(node, padding_override)
rhs = collapse(child)
elseif type == "call" then
local identifier = helpers.node_text(child:named_child(0))
child = child:named_child(1)
rhs = identifier .. collapse(child)
child = child:named_child(1)
rhs = identifier .. collapse(child)
elseif type == "boolean_operator" or
type == "parenthesized_expression" then
type == "parenthesized_expression" then
rhs = collapse(child)
end

Expand All @@ -177,8 +176,8 @@ end
local function find_row_parent(parent, parent_type, start_row)

while parent ~= nil and
parent_type ~= "if_statement" and
parent_type ~= "for_statement" do
parent_type ~= "if_statement" and
parent_type ~= "for_statement" do
parent = parent:parent()
if parent == nil then
return nil
Expand Down Expand Up @@ -212,7 +211,7 @@ local function skip_parens_by_reparenting(parent, parent_type)
local paren_parent = parent:parent()
local paren_parent_type = paren_parent:type()
if paren_parent_type == "assignment" or
paren_parent_type == "return_statement" then
paren_parent_type == "return_statement" then
parent = paren_parent
parent_type = paren_parent_type
end
Expand Down Expand Up @@ -252,7 +251,6 @@ local function collect_named_children(parent, children, comments)
end
end


--- @param if_statement TSNode
--- @return table
local function destructure_if_statement(if_statement)
Expand Down Expand Up @@ -337,18 +335,18 @@ local function expand_cond_expr(stmt, padding_override)
end

local start_row, start_col = parent:start()
local row_parent = find_row_parent(parent, parent_type, start_row)
local cursor = {}
local row_parent = find_row_parent(parent, parent_type, start_row)
local cursor = {}
-- when we are embedded on the end of an inlined if/for statement, we need
-- to expand on to the next line and shift the cursor/indent
local if_indent = ""
local else_indent = ""
local if_indent = ""
local else_indent = ""
if row_parent then
local _, row_start_col = row_parent:start()
-- cursor position is relative to the node being replaced (parent)
cursor = { row = 1, col = row_start_col - start_col + 4 }
if_indent = string.rep(" ", row_start_col + 4)
else_indent = if_indent
cursor = { row = 1, col = row_start_col - start_col + 4 }
if_indent = string.rep(" ", row_start_col + 4)
else_indent = if_indent
else
else_indent = string.rep(" ", start_col)
end
Expand Down Expand Up @@ -422,7 +420,7 @@ local function body_types_are_inlineable(cons_type, alt_type, cons_lhs, alt_lhs)
["parenthesized_expression"] = true,
}
return mixable_match_body_types[cons_type] and
mixable_match_body_types[alt_type]
mixable_match_body_types[alt_type]
end

--- @param stmt table { node, condition, consequence, alternative, comments }
Expand All @@ -444,25 +442,25 @@ local function inline_ifelse(stmt, padding_override)
stmt.alternative[1],
padding_override
)
if alt_rhs == nil or
not body_types_are_inlineable(cons_type, alt_type, cons_lhs, alt_lhs) then
if alt_rhs == nil or not body_types_are_inlineable(cons_type, alt_type, cons_lhs, alt_lhs) then
return
end

alt_rhs = parenthesize_if_needed(alt_child, alt_rhs)

local cond_text = collapse_child_nodes(padding_override)(stmt.condition)

local replacement = cons_lhs .. cons_rhs ..
" if " .. cond_text ..
" else " .. alt_rhs
" if " .. cond_text ..
" else " .. alt_rhs

return replacement, {
cursor = { col = string.len(cons_lhs .. cons_rhs) + 1 },
}
end

--- @param padding_override table
--- @return function
--- @return table
local function inline_if_statement(padding_override)
padding_override = padding_override or padding

Expand All @@ -474,6 +472,7 @@ local function inline_if_statement(padding_override)
if #stmt.consequence > 1 or #stmt.alternative > 1 then
return
end

if #stmt.comments > 0 then
return
end
Expand All @@ -498,17 +497,16 @@ local function inline_if_statement(padding_override)
end

--- @param padding_override table
--- @return function
--- @return table|nil
local function expand_conditional_expression(padding_override)
padding_override = padding_override or padding

--- @param conditional_expression TSNode
--- @return string, table, TSNode
local function action(conditional_expression)
local stmt = destructure_conditional_expression(conditional_expression)
if #stmt.comments > 0 then
return
end
if #stmt.comments > 0 then return end

return expand_cond_expr(stmt, padding_override)
end

Expand Down
25 changes: 13 additions & 12 deletions lua/ts-node-action/filetypes/ruby.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ local actions = require("ts-node-action.actions")

local padding = {
[","] = "%s ",
[":"] = "%s ",
[":"] = { "%s ", ["next_nil"] = "%s" },
["{"] = "%s ",
["=>"] = " %s ",
["="] = " %s ",
Expand All @@ -16,16 +16,17 @@ local padding = {

local identifier_formats = { "snake_case", "pascal_case", "screaming_snake_case" }

local uncollapsible = {
["conditional"] = true
}

local function toggle_block(node)
local structure = helpers.destructure_node(node)
if type(structure.body) == "table" then return end

local replacement

if helpers.node_is_multiline(node) then
if string.find(structure.body, "\n") then
print("(TS:Action) Cannot collapse multi-line block")
return
end

if structure.parameters then
replacement = "{ " .. structure.parameters .. " " .. structure.body .. " }"
else
Expand All @@ -43,7 +44,7 @@ local function toggle_block(node)
end

local function inline_conditional(structure)
if structure.consequence:match("\n") then
if type(structure.consequence) == "table" then
return
end

Expand All @@ -62,7 +63,7 @@ local function collapse_ternary(structure)
" ? ",
structure.consequence,
" : ",
vim.trim(string.gsub(structure.alternative, "else\n", ""))
structure.alternative[2]
}

return table.concat(replacement), { cursor = { col = #replacement[1] + 1 } }
Expand Down Expand Up @@ -130,10 +131,10 @@ return {
["identifier"] = actions.cycle_case(identifier_formats),
["constant"] = actions.cycle_case(identifier_formats),
["binary"] = actions.toggle_operator(),
["array"] = actions.toggle_multiline(padding),
["hash"] = actions.toggle_multiline(padding),
["argument_list"] = actions.toggle_multiline(padding),
["method_parameters"] = actions.toggle_multiline(padding),
["array"] = actions.toggle_multiline(padding, uncollapsible),
["hash"] = actions.toggle_multiline(padding, uncollapsible),
["argument_list"] = actions.toggle_multiline(padding, uncollapsible),
["method_parameters"] = actions.toggle_multiline(padding, uncollapsible),
["integer"] = actions.toggle_int_readability(),
["block"] = { { toggle_block, name = "Toggle Block" } },
["do_block"] = { { toggle_block, name = "Toggle Block" } },
Expand Down
Loading