Skip to content
This repository has been archived by the owner on Nov 23, 2024. It is now read-only.

paste truncated output in non pravite chats #87

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions src/eval/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async fn run_code(
const URL: &str = "https://play.rust-lang.org/execute";
let resp = client.post(URL).json(&req).send().await?;
let resp = resp.error_for_status()?.json().await?;
Ok(generate_result_from_response(resp, channel, is_private))
Ok(generate_result_from_response(client, resp, channel, is_private).await)
}

const PRELUDE: &str = include_str!("prelude.res.rs");
Expand Down Expand Up @@ -112,15 +112,41 @@ fn generate_code_to_send(code: &str, bare: bool) -> String {
)
}

fn generate_result_from_response(resp: Response, channel: Channel, is_private: bool) -> String {
async fn generate_result_from_response(
client: &Client,
resp: Response,
channel: Channel,
is_private: bool,
) -> String {
use std::borrow::Cow;
use std::fmt::Write;

if resp.success {
let output = resp.stdout.trim();
let output = if is_private {
output.into()
let output_ = resp.stdout.trim();

let output: Cow<'_, str> = if is_private {
output_.into()
} else {
const MAX_LINES: usize = 3;
const MAX_TOTAL_COLUMNS: usize = MAX_LINES * 72;
utils::truncate_output(output, MAX_LINES, MAX_TOTAL_COLUMNS)

if let (truncated_output, true) =
utils::truncate_output(output_, MAX_LINES, MAX_TOTAL_COLUMNS)
{
let mut output = truncated_output.into_owned();
match paste_to_pb(client, &output_).await {
Ok(pb_url) => {
let pb_url = pb_url.trim_end_matches('\n');
let _ = write!(output, "\n{pb_url}");
}
Err(e) => {
let _ = write!(output, "\nUnable to upload the full output:\n{e}");
}
}
return output.into();
} else {
output_.into()
}
};
if output.is_empty() {
return "(no output)".to_string();
Expand Down Expand Up @@ -178,6 +204,21 @@ fn generate_result_from_response(resp: Response, channel: Channel, is_private: b
}
}

#[allow(unused)]
const DPASTE_BASE_URL: &str = "https://paste.mozilla.org/";
const DPASTE_API_URL: &str = "https://paste.mozilla.org/api/";
/// result will be an url with an additional '\n'
async fn paste_to_pb(client: &Client, code: &str) -> reqwest::Result<String> {
let resp = client
.post(DPASTE_API_URL)
.form(&[("lexer", "rust"), ("content", code), ("format", "url")])
.send()
.await?
.text()
.await?;
Ok(resp)
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct Request {
Expand Down Expand Up @@ -271,4 +312,20 @@ mod tests {
assert_eq!(result, (header, body));
}
}

#[test]
fn test_paste_to_pastebin() {
let client = crate::build_client();

tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
let example_code = "fn main(){}";
assert!(paste_to_pb(&client, &example_code)
.await
.is_ok_and(|resp| resp.starts_with(DPASTE_BASE_URL)))
})
}
}
38 changes: 27 additions & 11 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ impl fmt::Display for Void {
}
}

pub fn truncate_output(output: &str, max_lines: usize, max_total_columns: usize) -> Cow<'_, str> {
pub fn truncate_output(
output: &str,
max_lines: usize,
max_total_columns: usize,
) -> (Cow<'_, str>, bool) {
let mut line_count = 0;
let mut column_count = 0;
for (pos, c) in output.char_indices() {
Expand All @@ -24,18 +28,18 @@ pub fn truncate_output(output: &str, max_lines: usize, max_total_columns: usize)
for (pos, c) in output[..pos].char_indices().rev() {
truncate_width += c.width_cjk().unwrap_or(1);
if truncate_width >= 3 {
return format!("{}...", &output[..pos]).into();
return (format!("{}...", &output[..pos]).into(), true);
}
}
}
if c == '\n' {
line_count += 1;
if line_count == max_lines {
return format!("{}...", &output[..pos]).into();
return (format!("{}...", &output[..pos]).into(), true);
}
}
}
output.into()
(output.into(), false)
}

pub fn is_message_from_private_chat(message: &Message) -> bool {
Expand Down Expand Up @@ -97,11 +101,12 @@ mod test {
fn construct_string(parts: &[(&str, usize)]) -> String {
let len = parts.iter().map(|(s, n)| s.len() * n).sum();
let mut result = String::with_capacity(len);
for &(s, n) in parts.iter() {
for _ in 0..n {
result.push_str(s);
}
}
result.extend(
parts
.iter()
.map(|&(s, n)| std::iter::once(s).cycle().take(n))
.flatten(),
);
result
}

Expand All @@ -112,33 +117,44 @@ mod test {
struct Testcase<'a> {
input: &'a [(&'a str, usize)],
expected: &'a [(&'a str, usize)],
truncated: bool,
}
const TESTCASES: &[Testcase<'_>] = &[
Testcase {
input: &[("a", 216)],
expected: &[("a", 216)],
truncated: false,
},
Testcase {
input: &[("a", 217)],
expected: &[("a", 213), ("...", 1)],
truncated: true,
},
Testcase {
input: &[("啊", 300)],
expected: &[("啊", 106), ("...", 1)],
truncated: true,
},
Testcase {
input: &[("啊", 107), ("a", 5)],
expected: &[("啊", 106), ("...", 1)],
truncated: true,
},
Testcase {
input: &[("a\n", 10)],
expected: &[("a\n", 2), ("a...", 1)],
truncated: true,
},
];
for Testcase { input, expected } in TESTCASES.iter() {
for Testcase {
input,
expected,
truncated,
} in TESTCASES.iter()
{
assert_eq!(
truncate_output(&construct_string(input), MAX_LINES, MAX_TOTAL_COLUMNS),
construct_string(expected)
(construct_string(expected).into(), *truncated)
);
}
}
Expand Down