Skip to content

non-bracket outer framing#205

Open
Felix-Kettnaker wants to merge 2 commits into
Wansmer:mainfrom
Felix-Kettnaker:feat/non-bracket-outer-framing
Open

non-bracket outer framing#205
Felix-Kettnaker wants to merge 2 commits into
Wansmer:mainfrom
Felix-Kettnaker:feat/non-bracket-outer-framing

Conversation

@Felix-Kettnaker

Copy link
Copy Markdown

⚠️ disclaimer: FYI: code for this PR is entirely written by AI 🤖.


support non_bracket nodes without a closing delimiter

What

Adds an opt-in non_bracket_node.outer_framing option (default true). Setting it to false stops a non_bracket node's format range from climbing to its parent's sibling when the node itself has no sibling on that side.

Why

search.range frames a non_bracket node by its surrounding siblings, falling back to the parent's sibling when the node has none:

local first = n:prev_sibling() or n:parent():prev_sibling()
local last  = n:next_sibling() or n:parent():next_sibling()

This is correct for languages whose blocks have an explicit closing delimiter token (e.g. Lua's then ... end, where the delimiter is a sibling). But indentation-based languages have no closing token (Python, GDScript, CoffeeScript, …). A block that is the last child of its parent then has no next_sibling, so the fallback grabs the following statement — the join range extends over it and swallows it. This currently makes it impossible to support split/join of :-introduced indented bodies.

Change

local climb = type(non_bracket_node) ~= 'table'
  or non_bracket_node.outer_framing ~= false

local function get_framing_for_non_bracket(n)
  local first = n:prev_sibling()
  local last = n:next_sibling()
  if climb then
    first = first or n:parent():prev_sibling()
    last = last or n:parent():next_sibling()
  end
  return first, last
end

With outer_framing = false, a missing side uses the node's own range instead of the parent's sibling.

Backward compatibility

Purely additive and opt-in — outer_framing defaults to true, so framing is byte-for-byte unchanged for every existing preset. Verified against an existing non_bracket language (Lua, round-trips with a following statement intact) and bracket presets (Python lists/dicts).

Example

A non_bracket block preset with outer_framing = false on Python's block:

Before (join swallows the next statement):

if cond: do_x()return

After:

if cond: do_x()
return

Notes

Language-independent — this is the missing piece for split/join of indentation-delimited blocks in general. A companion GDScript preset PR uses it to toggle one-line if/for/while/function bodies, but the flag is useful to any such language preset.

Tests

The flag needs a configured language to exercise through the test harness; its behavior is covered by a later GDScript preset modification PR (which needs the original GDScript template first), which uses outer_framing = false for statement bodies. I can also fold a test in here (e.g. demonstrating it on Python's block) if preferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant