| @@ -190,7 +190,7 @@ public enum Babel { |
| 190 | guard let m = line.firstMatch(of: #/(?i)^[ \t]*#\+CALL:[ \t]*([^\s(\[]+)(?:\[([^\]]*)\])?\((.*?)\)[ \t]*(.*?)[ \t]*\n?$/#) else { return nil } |
190 | guard let m = line.firstMatch(of: #/(?i)^[ \t]*#\+CALL:[ \t]*([^\s(\[]+)(?:\[([^\]]*)\])?\((.*?)\)[ \t]*(.*?)[ \t]*\n?$/#) else { return nil } |
| 191 | let name = String(m.1) |
191 | let name = String(m.1) |
| 192 | guard let block = model.srcBlocks.first(where: { $0.name == name }) else { throw Failure.message("Reference '\(name)' not found in this buffer") } |
192 | guard let block = model.srcBlocks.first(where: { $0.name == name }) else { throw Failure.message("Reference '\(name)' not found in this buffer") } |
| 193 | var extra = [lobDefaults] |
193 | var extra = [lobDefaults] + callProperties(block, at: lineRange.location, model: model) |
| 194 | if let inside = m.2 { extra.append(Params.parse(String(inside))) } |
194 | if let inside = m.2 { extra.append(Params.parse(String(inside))) } |
| 195 | extra.append(splitArguments(String(m.3)).map { (":var", $0) }) |
195 | extra.append(splitArguments(String(m.3)).map { (":var", $0) }) |
| 196 | if !m.4.isEmpty { extra.append(Params.parse(String(m.4))) } |
196 | if !m.4.isEmpty { extra.append(Params.parse(String(m.4))) } |
| @@ -216,13 +216,20 @@ public enum Babel { |
| 216 | guard let object = found, let m = object.text.firstMatch(of: /^call_([^()\[\]\s]+)(?:\[([^\]]*)\])?\((.*?)\)(?:\[([^\]]*)\])?$/) else { return nil } |
216 | guard let object = found, let m = object.text.firstMatch(of: /^call_([^()\[\]\s]+)(?:\[([^\]]*)\])?\((.*?)\)(?:\[([^\]]*)\])?$/) else { return nil } |
| 217 | let name = String(m.1) |
217 | let name = String(m.1) |
| 218 | guard let block = model.srcBlocks.first(where: { $0.name == name }) else { throw Failure.message("Reference '\(name)' not found in this buffer") } |
218 | guard let block = model.srcBlocks.first(where: { $0.name == name }) else { throw Failure.message("Reference '\(name)' not found in this buffer") } |
| 219 | var extra = [lobDefaults] |
219 | var extra = [lobDefaults] + callProperties(block, at: object.range.lowerBound, model: model) |
| 220 | if let inside = m.2 { extra.append(Params.parse(String(inside))) } |
220 | if let inside = m.2 { extra.append(Params.parse(String(inside))) } |
| 221 | extra.append(splitArguments(String(m.3)).map { (":var", $0) }) |
221 | extra.append(splitArguments(String(m.3)).map { (":var", $0) }) |
| 222 | if let end = m.4 { extra.append(Params.parse(String(end))) } |
222 | if let end = m.4 { extra.append(Params.parse(String(end))) } |
| 223 | return (block, try Params(block: block, model: model, text: text, extra: extra), object.range) |
223 | return (block, try Params(block: block, model: model, text: text, extra: extra), object.range) |
| 224 | } |
224 | } |
| 225 | |
225 | |
| |
226 | /// The `header-args` properties where a call is, in the called block's language, which |
| |
227 | /// `org-babel-lob-get-info` puts after `lobDefaults`. |
| |
228 | static func callProperties(_ block: SrcBlockInfo, at location: Int, model: DocumentModel) -> [[(String, String)]] { |
| |
229 | let heading = model.headings.lastIndex { $0.headingRange.lowerBound <= location } |
| |
230 | return Params.propertyLayers(language: block.language ?? "", heading: heading, model: model) |
| |
231 | } |
| |
232 | |
| 226 | /// `org-babel-default-lob-header-args`, over the called block's own header arguments. |
233 | /// `org-babel-default-lob-header-args`, over the called block's own header arguments. |
| 227 | static let lobDefaults = [(":exports", "results")] |
234 | static let lobDefaults = [(":exports", "results")] |
| 228 | |
235 | |
| @@ -246,7 +253,9 @@ public enum Babel { |
| 246 | if line.range(of: "(?i)^[ \\t]*#\\+CALL:", options: .regularExpression) != nil { |
253 | if line.range(of: "(?i)^[ \\t]*#\\+CALL:", options: .regularExpression) != nil { |
| 247 | call = (try? callAt(offset, model: model, text: text))?.params |
254 | call = (try? callAt(offset, model: model, text: text))?.params |
| 248 | } else if tree.root.descendants().contains(where: { $0.kind == .inlineBabelCall && $0.range.lowerBound == offset }) { |
255 | } else if tree.root.descendants().contains(where: { $0.kind == .inlineBabelCall && $0.range.lowerBound == offset }) { |
| 249 | call = (try? inlineCallAt(offset, tree: tree, model: model, text: text))?.params |
256 | // `org-babel-remove-result` only takes away `#+RESULTS:`, so an inline call's |
| |
257 | // `{{{results(...)}}}` stays whatever `:exports` says. |
| |
258 | return "results" |
| 250 | } else if let inline = try? inlineAt(offset, tree: tree, model: model, text: text), inline.block.range.lowerBound == offset { |
259 | } else if let inline = try? inlineAt(offset, tree: tree, model: model, text: text), inline.block.range.lowerBound == offset { |
| 251 | return value(inline.params, language: inline.block.language) |
260 | return value(inline.params, language: inline.block.language) |
| 252 | } else { |
261 | } else { |
| @@ -924,22 +933,7 @@ public enum Babel { |
| 924 | init(block: SrcBlockInfo, model: DocumentModel, text: NSString, defaults: [(String, String)] = [], extra: [[(String, String)]] = [], |
933 | init(block: SrcBlockInfo, model: DocumentModel, text: NSString, defaults: [(String, String)] = [], extra: [[(String, String)]] = [], |
| 925 | inline: Bool = false) throws { |
934 | inline: Bool = false) throws { |
| 926 | var layers: [[(String, String)]] = [defaults] |
935 | var layers: [[(String, String)]] = [defaults] |
| 927 | let language = block.language ?? "" |
936 | layers += Params.propertyLayers(language: block.language ?? "", heading: block.heading, model: model) |
| 928 | // `org-babel-params-from-properties`: the inherited `header-args`, then the inherited |
| |
| 929 | // `header-args:LANG`, each the nearest value with `+` additions after it. |
| |
| 930 | var levels = [model.fileProperties] |
| |
| 931 | if let heading = block.heading { |
| |
| 932 | levels += (model.ancestors(of: heading).reversed() + [heading]).map { model.headings[$0].properties } |
| |
| 933 | } |
| |
| 934 | for key in ["header-args", "header-args:\(language)"] { |
| |
| 935 | var value: String? |
| |
| 936 | for entries in levels { |
| |
| 937 | for entry in entries where entry.key.lowercased() == key { |
| |
| 938 | value = entry.additive ? [value, entry.value].compactMap { $0 }.joined(separator: " ") : entry.value |
| |
| 939 | } |
| |
| 940 | } |
| |
| 941 | if let value { layers.append(Params.parse(value)) } |
| |
| 942 | } |
| |
| 943 | let firstLine = inline ? "" : text.substring(with: text.lineRange(for: NSRange(location: block.range.lowerBound, length: 0))) |
937 | let firstLine = inline ? "" : text.substring(with: text.lineRange(for: NSRange(location: block.range.lowerBound, length: 0))) |
| 944 | if let r = firstLine.range(of: "(?i)#\\+begin_src[ \\t]+\\S+", options: .regularExpression) { |
938 | if let r = firstLine.range(of: "(?i)#\\+begin_src[ \\t]+\\S+", options: .regularExpression) { |
| 945 | var rest = String(firstLine[r.upperBound...]).trimmingCharacters(in: .whitespacesAndNewlines) |
939 | var rest = String(firstLine[r.upperBound...]).trimmingCharacters(in: .whitespacesAndNewlines) |
| @@ -993,6 +987,25 @@ public enum Babel { |
| 993 | } |
987 | } |
| 994 | } |
988 | } |
| 995 | |
989 | |
| |
990 | /// `org-babel-params-from-properties` under `heading`, or before any: the inherited |
| |
991 | /// `header-args`, then the inherited `header-args:LANG`, each the nearest value with `+` |
| |
992 | /// additions after it. |
| |
993 | static func propertyLayers(language: String, heading: Int?, model: DocumentModel) -> [[(String, String)]] { |
| |
994 | var levels = [model.fileProperties] |
| |
995 | if let heading { |
| |
996 | levels += (model.ancestors(of: heading).reversed() + [heading]).map { model.headings[$0].properties } |
| |
997 | } |
| |
998 | return ["header-args", "header-args:\(language)"].compactMap { key in |
| |
999 | var value: String? |
| |
1000 | for entries in levels { |
| |
1001 | for entry in entries where entry.key.lowercased() == key { |
| |
1002 | value = entry.additive ? [value, entry.value].compactMap { $0 }.joined(separator: " ") : entry.value |
| |
1003 | } |
| |
1004 | } |
| |
1005 | return value.map(Params.parse) |
| |
1006 | } |
| |
1007 | } |
| |
1008 | |
| 996 | /// `org-babel-parse-header-arguments`: split before each `:key` outside quotes and |
1009 | /// `org-babel-parse-header-arguments`: split before each `:key` outside quotes and |
| 997 | /// parentheses. |
1010 | /// parentheses. |
| 998 | /// A Lisp string's contents as `read` gives them. |
1011 | /// A Lisp string's contents as `read` gives them. |