ek9_surround_with
Folds a contiguous line range under an if / if-else / try-catch / try-catch-finally / for-range / while head, re-indenting the block per EK9's brace-free rules; answers status and edits[] (one REPLACE carrying the head + the re-indented lines, one DELETE per absorbed line).
When to use it
'Wrap those lines in an if on count > 0' is one call with file, fromText (the block's first line as written), toText (its last), surroundType:'if', condition:'count > 0' - the tool owns the re-indent. Use it on a contiguous range of WHOLE statements at one indent level that should run conditionally, loop, or be exception-handled.
When not to use it
- You want EK9's idiomatic guard form (<-, :=?) for a null/unset check, not a generic if wrap — use
ek9_apply_guard_pattern. - You want to factor the block into a named method rather than wrap it — use
ek9_extract_method. - You want to convert an imperative loop into a stream pipeline — use
ek9_advise_loop. - You want to wrap a single expression in a coalescing/elvis operator — use
ek9_insert_coalescing.
Details
Head text you pass (condition for if/if-else/while, rangeExpression for for-range, exceptionType/exceptionVariable for try-catch) is parsed alone first - a text that does not parse is status:error with nothing written - then emitted verbatim. An omitted head is an opaque placeholder for the caller to edit: `if` inserts `surroundGuard <- Boolean(true)` then `if surroundGuard? //AI:`, `while` inserts `loopGuard <- Boolean(false)` then `while loopGuard //AI:`, `for-range` inserts `for i in 1 ... 10 //AI:` (a bare `true` would trip E07390 pointless-condition). Wrapped lines are re-indented +2 spaces; the head line(s) sit at the block's current indent; a line range outside the file or endLine < startLine is a hard error.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
condition | string | if / if-else / while: the condition source text (e.g. 'count > 0', 'name?'), emitted verbatim. Omitted: an opaque placeholder guard with an //AI: marker to replace. | |
endLine | integer | Or the last line of the selection (1-based, inclusive). | |
exceptionType | string | try-catch / try-catch-finally: the caught type (default Exception). | |
exceptionVariable | string | try-catch / try-catch-finally: the handler's variable name (default ex). | |
file | string | yes | Workspace-relative path to the .ek9 source file containing the lines to wrap. |
fromText | string | The block's FIRST line exactly as written (indentation ignored) - instead of counting startLine. Must name one line; add more of it when it occurs twice. | |
rangeExpression | string | for-range: the text after 'for i in' (e.g. '1 ... 10', 'items'), or a whole 'item in items' clause. Omitted: 'for i in 1 ... 10 //AI: Replace range'. | |
startLine | integer | Or the first line of the selection (1-based) - an IDE selection. | |
surroundType | string: if | if-else | try-catch | try-catch-finally | for-range | while | yes | The wrapper: if, if-else, try-catch, try-catch-finally, for-range or while. |
toText | string | The block's LAST line as written - the first line matching it at or after fromText. Omit it for a one-line block. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 4 recorded are shown.
Surround with condition does not parse
Request
{
"condition" : "count >",
"endLine" : 8,
"file" : "Hello.ek9",
"startLine" : 8,
"surroundType" : "if"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "condition does not parse as EK9: extraneous indentation expecting valid statement or expression near 'indentation' - fix the text, or omit it for a placeholder head"
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "condition does not parse as EK9: extraneous indentation expecting valid statement or expression near 'indentation' - fix the text, or omit it for a placeholder head",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Surround with from text apply
Request
{
"condition" : "count > 0",
"file" : "Hello.ek9",
"fromText" : "stdout.println($count)",
"surroundType" : "if",
"toText" : "stdout.println($count)"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " if count > 0\n stdout.println($count)",
"before" : " stdout.println($count)",
"endLine" : 8,
"file" : "Hello.ek9",
"startLine" : 8,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/Hello.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Surrounded lines 8-8 with if",
...
Cut short here: 4 more lines. The whole recorded call.
Surround with if condition apply
Request
{
"condition" : "count > 0",
"endLine" : 8,
"file" : "Hello.ek9",
"startLine" : 8,
"surroundType" : "if"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " if count > 0\n stdout.println($count)",
"before" : " stdout.println($count)",
"endLine" : 8,
"file" : "Hello.ek9",
"startLine" : 8,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/Hello.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Surrounded lines 8-8 with if",
...
Cut short here: 4 more lines. The whole recorded call.
See also
- Show me in the IDE: Chapter 3: a loop, reshaped
- Show me in the IDE: Chapter 11: Optional and Result, built
- Show me in the IDE: Surround With