///|
priv struct HostIO {
mut invoke : ((String, Array[String]) -> Result[String, String])?
}
///|
impl Debug for HostIO with fn to_repr(_self) {
Repr("HostIO")
}
///|
/// Install a synchronous host filesystem/channel adapter. The core never
/// accesses operating-system files unless the embedding application supplies it.
pub fn Interpreter::set_io(
self : Interpreter,
callback : (String, Array[String]) -> Result[String, String],
) -> Unit {
self.state.host_io.invoke = Some(callback)
}
///|
fn Interpreter::host_call(
self : Interpreter,
name : String,
args : Array[String],
) -> String raise TclError {
match self.state.host_io.invoke {
Some(invoke) =>
match invoke(name, args) {
Ok(value) => value
Err(message) => raise Invalid(message)
}
None => raise Invalid("filesystem adapter is not configured")
}
}
///|
fn Interpreter::io_command(
self : Interpreter,
values : Array[TclValue],
depth : Int,
) -> TclValue raise TclError {
let args = values.map(v => v.text)
let name = args[0]
if name == "source" {
let filename = if args.length() == 2 {
args[1]
} else if args.length() == 4 && args[1] == "-encoding" {
args[3]
} else {
raise Invalid("source ?-encoding name? fileName")
}
let source = self.host_call("source", args[1:].to_owned())
let previous = self.state.script_name.val
self.state.script_name.val = filename
defer {
self.state.script_name.val = previous
}
let result = self.capture(source, depth + 1)
let result = if result.level > 0 {
{ ..result, level: result.level - 1, }
} else {
result
}
return self.propagate_value(result)
}
if name == "gets" {
if args.length() != 2 && args.length() != 3 {
raise Invalid("gets channelId ?varName?")
}
// Prefix 0 is a line, prefix 1 is EOF. This preserves an empty final line.
let result = self.host_call("gets", [args[1]])
if !result.has_prefix("0") && result != "1" {
raise Invalid("invalid host line response")
}
let eof = result == "1"
let line = if eof { "" } else { result[1:].to_owned() }
if args.length() == 3 {
self.set_var(args[2], line)
return text_value(if eof { "-1" } else { line.length().to_string() })
}
return text_value(line)
}
text_value(self.host_call(name, args[1:].to_owned()))
}