Run inline babel calls !129

merged merged by cmc on 2026-10-07 05:35 UTC · krz/orgstar:inline-calls into main

2 files changed, +28 −0

Layout: unified · split

Sources/OrgCore/Compute/Babel.swift +22
@@ -138,6 +138,9 @@ public enum Babel {
138 if let call = try callAt(context.caret, model: model, text: ns) { 138 if let call = try callAt(context.caret, model: model, text: ns) {
139 return located(plan(call.block, params: call.params, model: model, text: ns, options: options, location: call.location, name: call.name, refs: refs)) 139 return located(plan(call.block, params: call.params, model: model, text: ns, options: options, location: call.location, name: call.name, refs: refs))
140 } 140 }
141 if let call = try inlineCallAt(context.caret, tree: context.tree, model: model, text: ns) {
142 return located(plan(call.block, params: call.params, model: model, text: ns, options: options, location: call.location, name: nil, inline: true, refs: refs))
143 }
141 if let inline = try inlineAt(context.caret, tree: context.tree, model: model, text: ns) { 144 if let inline = try inlineAt(context.caret, tree: context.tree, model: model, text: ns) {
142 return located(plan(inline.block, params: inline.params, model: model, text: ns, options: options, location: inline.block.range, name: nil, inline: true, refs: refs)) 145 return located(plan(inline.block, params: inline.params, model: model, text: ns, options: options, location: inline.block.range, name: nil, inline: true, refs: refs))
143 } 146 }
@@ -171,6 +174,25 @@ public enum Babel {
171 return (block, try Params(block: block, model: model, text: text, extra: extra), location, callName) 174 return (block, try Params(block: block, model: model, text: text, extra: extra), location, callName)
172 } 175 }
173 176
177 /// The inline `call_NAME[INSIDE](ARGS)[END]` at `offset`: like `#+CALL`, with the result
178 /// after the call.
179 static func inlineCallAt(_ offset: Int, tree: OrgTree, model: DocumentModel, text: NSString) throws -> (block: SrcBlockInfo, params: Params, location: Range<Int>)? {
180 var node = tree.root
181 var found: SyntaxNode?
182 while let child = node.child(containing: offset) {
183 if child.kind == .inlineBabelCall { found = child }
184 node = child
185 }
186 guard let object = found, let m = object.text.firstMatch(of: /^call_([^()\[\]\s]+)(?:\[([^\]]*)\])?\((.*?)\)(?:\[([^\]]*)\])?$/) else { return nil }
187 let name = String(m.1)
188 guard let block = model.srcBlocks.first(where: { $0.name == name }) else { throw Failure.message("Reference '\(name)' not found in this buffer") }
189 var extra: [[(String, String)]] = []
190 if let inside = m.2 { extra.append(Params.parse(String(inside))) }
191 extra.append(splitArguments(String(m.3)).map { (":var", $0) })
192 if let end = m.4 { extra.append(Params.parse(String(end))) }
193 return (block, try Params(block: block, model: model, text: text, extra: extra), object.range)
194 }
195
174 /// Call arguments split on commas outside quotes and parentheses. 196 /// Call arguments split on commas outside quotes and parentheses.
175 static func splitArguments(_ s: String) -> [String] { 197 static func splitArguments(_ s: String) -> [String] {
176 var parts: [String] = [] 198 var parts: [String] = []
Tests/OrgCoreTests/BabelTests.swift +6
@@ -196,6 +196,12 @@ struct BabelCallTests {
196 ("Text src_sh[:results raw]{echo raw} end.\n", "src_sh"), 196 ("Text src_sh[:results raw]{echo raw} end.\n", "src_sh"),
197 ("Text src_python{return 6*7} end.\n", "src_python"), 197 ("Text src_python{return 6*7} end.\n", "src_python"),
198 ("Text src_sh[:var x=3]{echo $x} end.\n", "src_sh"), 198 ("Text src_sh[:var x=3]{echo $x} end.\n", "src_sh"),
199 (named + "Inline call_double(n=6) here.\n", "call_"),
200 (named + "Inline call_double() here.\n", "call_"),
201 (named + "Inline call_double(n=6)[:results raw] here.\n", "call_"),
202 (named + "Inline call_double[:results verbatim](n=1) here.\n", "call_"),
203 (named + "Inline call_double(n=2) {{{results(=0=)}}} here.\n", "call_"),
204 (named + "Inline call_double(n=2) and call_double(n=3) here.\n", "call_double(n=3"),
199 ] 205 ]
200 206
201 @Test(.enabled(if: ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil)) 207 @Test(.enabled(if: ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil))