html terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use super::{Context, Result};
use lemu::Executor;
use poise::{serenity_prelude::AttachmentType, KeyValueArgs};
use regex::Regex;
use std::{borrow::Cow, sync::LazyLock};

#[poise::command(prefix_command, category = "Misc", track_edits, rename = "eval")]
pub async fn run(
    ctx: Context<'_>,
    #[description = "number of iterations"] kv: KeyValueArgs,
    #[rest]
    #[description = "Script"]
    from: String,
) -> Result<()> {
    let _ = ctx.channel_id().start_typing(&ctx.serenity_context().http);

    static RE: LazyLock<Regex> =
        LazyLock::new(|| Regex::new(r#"```(arm|x86asm)?([^`]+)```"#).unwrap());

    let lemu::Output {
        output: Some(output),
        displays,
        ..
    } = ({
        let mat = RE
            .captures(&from)
            .ok_or(anyhow::anyhow!(r#"no code found (use \`\`\`arm...\`\`\`."#))?;
        let script = mat.get(2).unwrap().as_str();
        match Executor::with_output(vec![])
            .display()
            .limit_iterations(
                kv.get("iters")
                    .map_or(1, |v| v.parse::<usize>().unwrap_or(1).clamp(1, 50)),
            )
            .limit_instructions(30000)
            .program(&script)
        {
            Ok(mut v) => {
                v.run();
                v.output()
            }
            Err(e) => {
                let s = format!("{}", e.diagnose(script)).replace("`", "\u{200b}`");
                ctx.send(|c| {
                    c.allowed_mentions(|a| a.empty_parse())
                        .content(format!("```ansi\n{s}\n```"))
                })
                .await?;
                return Ok(());
            }
        }
    })
    else {
        unreachable!()
    };
    let displays: Box<[_; 1]> = displays.try_into().unwrap();
    let [display] = *displays;

    ctx.send(|c| {
        let mut empty = true;
        if !output.is_empty() {
            c.content(format!(
                "```\n{}\n```",
                String::from_utf8_lossy(&output).replace('`', "\u{200b}`")
            ));
            empty = false;
        }
        if display.buffer().iter().any(|&n| n != 0) {
            let p = oxipng::RawImage::new(
                display.width(),
                display.height(),
                oxipng::ColorType::RGBA,
                oxipng::BitDepth::Eight,
                display.take_buffer(),
            )
            .unwrap();
            let p = p
                .create_optimized_png(&oxipng::Options {
                    filter: oxipng::indexset! { oxipng::RowFilter::None },
                    bit_depth_reduction: false,
                    color_type_reduction: false,
                    palette_reduction: false,
                    grayscale_reduction: false,
                    ..oxipng::Options::from_preset(0)
                })
                .unwrap();
            c.attachment(AttachmentType::Bytes {
                data: Cow::from(p),
                filename: "display1.png".to_string(),
            });
            c.embed(|e| e.attachment("display1.png"));
            empty = false;
        }
        if empty {
            c.content("no output");
        }
        c.allowed_mentions(|a| a.empty_parse())
    })
    .await?;

    Ok(())
}