retex-lua 1.0.0

Embedded Lua and the LuaTeX Lua API for retex
Documentation
//! The `texio` library (LuaTeX manual ยง10.6).

use mlua::{Lua, MultiValue, Value};
use retex_engine::print::Selector;

use crate::with_engine;

/// Installs `texio`.
pub fn install(lua: &Lua) -> mlua::Result<()> {
    let t = lua.create_table()?;
    t.set(
        "write",
        lua.create_function(|lua, args: MultiValue| write(lua, args, false))?,
    )?;
    t.set(
        "write_nl",
        lua.create_function(|lua, args: MultiValue| write(lua, args, true))?,
    )?;
    t.set("setescape", lua.create_function(|_, _v: Value| Ok(()))?)?;
    t.set("closeinput", lua.create_function(|_, ()| Ok(()))?)?;
    lua.globals().set("texio", t)?;
    Ok(())
}

/// The selector named by a `texio` target string.
fn target(s: &[u8], current: Selector, log_open: bool) -> Option<Selector> {
    match s {
        b"term" => Some(Selector::TermOnly),
        b"log" => Some(if log_open {
            Selector::LogOnly
        } else {
            Selector::NoPrint
        }),
        b"term and log" => Some(if log_open {
            Selector::TermAndLog
        } else {
            Selector::TermOnly
        }),
        _ => {
            let _ = current;
            None
        }
    }
}

fn write(lua: &Lua, args: MultiValue, nl: bool) -> mlua::Result<()> {
    let mut v: Vec<Value> = args.into_iter().collect();
    let mut sel_override = None;
    if v.len() > 1
        && let Some(Value::String(s)) = v.first()
    {
        let b = s.as_bytes().to_vec();
        let t = with_engine(lua, |e| {
            target(&b, e.printer.selector, e.printer.log_opened())
        })?;
        if t.is_some() {
            sel_override = t;
            v.remove(0);
        }
    }
    let mut texts: Vec<Vec<u8>> = Vec::new();
    for x in &v {
        match x {
            Value::String(s) => texts.push(s.as_bytes().to_vec()),
            Value::Integer(n) => texts.push(n.to_string().into_bytes()),
            Value::Number(n) => texts.push(crate::texlib::lua_number_string(*n).into_bytes()),
            _ => {}
        }
    }
    with_engine(lua, |e| {
        let old = e.printer.selector;
        if let Some(s) = sel_override {
            e.printer.selector = s;
        } else if e.printer.selector == Selector::NoPrint && e.printer.log_opened() {
            e.printer.selector = Selector::LogOnly;
        }
        if nl {
            e.printer.begin_line();
        }
        for t in &texts {
            e.printer.print_lua_bytes(t);
        }
        e.printer.update_terminal();
        e.printer.selector = old;
    })
}