html terminal
-rw-r--r--Cargo.toml1
-rw-r--r--src/bot/mod.rs52
-rw-r--r--src/bot/schematic.rs31
-rw-r--r--src/process.rs6
4 files changed, 60 insertions, 30 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9c96202..1201178 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,6 +42,7 @@ btparse = "0.1.1"
mindus = { version = "3", features = [], default-features = false }
image = { version = "0.24.6", features = ["png"], default-features = false }
oxipng = { git = "https://github.com/shssoichiro/oxipng", branch = "master", features = [], default-features = false }
+strip-ansi-escapes = "0.1.2"
[profile.release]
strip = true
diff --git a/src/bot/mod.rs b/src/bot/mod.rs
index 3809c4e..b56c23c 100644
--- a/src/bot/mod.rs
+++ b/src/bot/mod.rs
@@ -14,8 +14,8 @@ use maps::Maps;
use serenity::http::Http;
use serenity::prelude::*;
+use std::fmt::Write;
use std::fs::read_to_string;
-use std::str::FromStr;
use std::sync::{
atomic::{AtomicU8, Ordering},
Arc, OnceLock,
@@ -121,28 +121,38 @@ async fn on_error(error: poise::FrameworkError<'_, Data, anyhow::Error>) {
use poise::FrameworkError::Command;
match error {
Command { error, ctx } => {
- ctx.say(format!("e: `{error}`")).await.unwrap();
- if let Ok(n) = std::env::var("RUST_LIB_BACKTRACE")
- && let Ok(n) = u8::from_str(&n)
- && n == 1 {
- let mut parsed = btparse::deserialize(dbg!(error.backtrace())).unwrap();
- let mut s = vec![];
- for frame in &mut parsed.frames {
- if let Some(line) = frame.line.take()
- && (frame.function.contains("panel")
- || frame.function.contains("poise")
- || frame.function.contains("serenity"))
- {
- s.push(format!("l{}@{}", line, frame.function));
- }
-
+ let mut msg;
+ {
+ let mut chain = error.chain();
+ msg = format!("e: `{}`", chain.next().unwrap());
+ for mut source in chain {
+ write!(msg, "from: `{source}`").unwrap();
+ loop {
+ let Some(next) = source.source() else { break };
+ write!(msg, "from: `{next}`").unwrap();
+ source = next;
}
- s.truncate(15);
- ctx.say(format!("trace: ```rs\n{}\n```", s.join("\n")))
- .await
- .unwrap();
-
+ }
}
+ let bt = error.backtrace();
+ if bt.status() == std::backtrace::BacktraceStatus::Captured {
+ let parsed = btparse::deserialize(dbg!(error.backtrace())).unwrap();
+ let mut s = vec![];
+ for frame in parsed.frames {
+ if let Some(line) = frame.line
+ && (frame.function.contains("panel")
+ || frame.function.contains("poise")
+ || frame.function.contains("serenity")
+ || frame.function.contains("mindus")
+ || frame.function.contains("image"))
+ {
+ s.push(format!("l{}@{}", line, frame.function));
+ }
+ }
+ s.truncate(15);
+ write!(msg, "trace: ```rs\n{}\n```", s.join("\n")).unwrap();
+ }
+ ctx.say(msg).await.unwrap();
}
err => poise::builtins::on_error(err).await.unwrap(),
}
diff --git a/src/bot/schematic.rs b/src/bot/schematic.rs
index 2d618d8..2499ca9 100644
--- a/src/bot/schematic.rs
+++ b/src/bot/schematic.rs
@@ -1,8 +1,8 @@
use super::{strip_colors, Context, SUCCESS};
use anyhow::{anyhow, Result};
-use image::{codecs::png::PngEncoder, ImageEncoder};
use mindus::data::{DataRead, DataWrite, Serializer};
use mindus::*;
+use oxipng::*;
use poise::serenity_prelude::*;
use regex::Regex;
use std::borrow::Cow;
@@ -34,7 +34,8 @@ pub async fn context_draw(ctx: Context<'_>, msg: Message) -> Result<()> {
prefix_command,
slash_command,
category = "Info",
- rename = "draw_schematic"
+ rename = "draw_schematic",
+ track_edits
)]
/// draw schematic.
pub async fn draw(ctx: Context<'_>, schematic: String) -> Result<()> {
@@ -43,10 +44,28 @@ pub async fn draw(ctx: Context<'_>, schematic: String) -> Result<()> {
}
async fn send(ctx: &Context<'_>, s: &Schematic<'_>, send_schematic: bool) -> Result<()> {
- let mut b = vec![];
- let p = unsafe { s.render() };
- PngEncoder::new(&mut b).write_image(&p, p.width(), p.height(), image::ColorType::Rgba8)?;
let n = strip_colors(s.tags.get("name").unwrap());
+ let p = unsafe { s.render() };
+ let p = RawImage::new(
+ p.width(),
+ p.height(),
+ ColorType::RGB {
+ transparent_color: None,
+ },
+ BitDepth::Eight,
+ p.into_vec(),
+ )
+ .unwrap();
+ let p = p
+ .create_optimized_png(&oxipng::Options {
+ filter: indexset! { RowFilter::None },
+ bit_depth_reduction: false,
+ color_type_reduction: false,
+ palette_reduction: false,
+ grayscale_reduction: false,
+ ..oxipng::Options::from_preset(0)
+ })
+ .unwrap();
poise::send_reply(*ctx, |m| {
if send_schematic {
let mut out = DataWrite::default();
@@ -57,7 +76,7 @@ async fn send(ctx: &Context<'_>, s: &Schematic<'_>, send_schematic: bool) -> Res
});
}
m.attachment(AttachmentType::Bytes {
- data: Cow::Owned(b),
+ data: Cow::Owned(p),
filename: "image.png".to_string(),
})
.embed(|e| {
diff --git a/src/process.rs b/src/process.rs
index 4639531..c13332c 100644
--- a/src/process.rs
+++ b/src/process.rs
@@ -51,7 +51,7 @@ impl Process {
},
Ok(mut s) => {
input!("{s}");
- s += "\n";
+ s.push_str("\n");
self.inner.write_all(s.as_bytes()).await.unwrap();
self.inner.flush().await.unwrap();
}
@@ -59,10 +59,10 @@ impl Process {
let string = {
let n = tokio::select! {
- n = {self.inner.read(&mut stdout)} => n.unwrap(),
+ n = self.inner.read(&mut stdout) => n.unwrap(),
_ = sleep(Duration::from_millis(500)) => continue,
};
- String::from_utf8_lossy(&stdout[..n]).into_owned()
+ String::from_utf8_lossy(&strip_ansi_escapes::strip(&stdout[..n])).into_owned()
};
for line in string.lines() {
output!("{line}");