tangled
alpha
login
or
join now
isabelroses.com
/
blahaj
1
fork
atom
silly goober bot
1
fork
atom
overview
issues
pulls
pipelines
chore: cleanup code expantion
isabelroses.com
2 years ago
3c2bd7ee
265163d8
+79
-95
1 changed file
expand all
collapse all
unified
split
src
event_handler
code_expantion.rs
+79
-95
src/event_handler/code_expantion.rs
···
1
// the logic here is pretty much ripped from https://github.com/uncenter/discord-forum-bot/blob/main/src/modules/expandGitHubLinks.ts
2
// with some modifications so I can make it work on diffrent git hosts
3
4
-
use color_eyre::eyre::Result;
5
-
use poise::serenity_prelude::{self as serenity, Context, CreateMessage, FullEvent};
6
use regex::Regex;
7
use reqwest::Client;
8
9
pub async fn handle(ctx: &Context, event: &FullEvent) -> Result<()> {
10
if let FullEvent::Message { new_message } = event {
11
-
let mut embeds: Vec<serenity::CreateEmbed> = Vec::new();
12
13
-
embeds.extend(github_compatable_embeds(new_message.content.clone()).await?);
14
-
15
-
if !embeds.is_empty() {
16
new_message
17
.channel_id
18
-
.send_message(&ctx, CreateMessage::default().embeds(embeds))
19
.await?;
20
}
21
}
···
23
Ok(())
24
}
25
26
-
async fn github_compatable_embeds(msg: String) -> Result<Vec<serenity::CreateEmbed>> {
27
let re = Regex::new(
28
-
r"https?://(?P<host>(git.*|codeberg\.org))/(?P<repo>[\w-]+/[\w.-]+)/(blob|(src/(commit|branch)))?/(?P<reference>\S+?)/(?P<file>\S+)#L(?P<start>\d+)(?:[~-]L?(?P<end>\d+)?)?"
29
-
).unwrap();
30
31
-
let mut embeds: Vec<serenity::CreateEmbed> = Vec::new();
0
32
33
-
let mut code_blocks = Vec::new();
34
for caps in re.captures_iter(&msg) {
35
-
let host = &caps["host"];
36
-
let repo = &caps["repo"];
37
-
let reference = &caps["reference"];
38
-
let file = &caps["file"];
39
-
let language = file.split('.').last().unwrap_or("").to_string();
40
41
-
let start = caps["start"].parse::<usize>().unwrap_or(1);
42
-
let end = caps
43
-
.name("end")
44
-
.and_then(|end| end.as_str().parse::<usize>().ok())
45
-
.unwrap_or(start);
46
47
-
let raw_url = if host == "github.com" {
48
-
format!("https://raw.githubusercontent.com/{repo}/{reference}/{file}")
49
-
} else {
50
-
let refer = if reference.len() == 40 {
51
-
format!("commit/{reference}")
52
-
} else {
53
-
format!("branch/{reference}")
54
-
};
55
-
format!("https://{host}/{repo}/raw/{refer}/{file}")
56
-
};
57
58
-
let response = Client::new().get(&raw_url).send().await;
0
59
60
-
if let Ok(response) = response {
61
-
if !response.status().is_success() {
62
-
println!("Failed to fetch content.");
63
-
continue;
64
-
}
0
0
0
0
0
0
65
66
-
let text = response.text().await?;
67
-
let mut content = text
68
-
.lines()
69
-
.skip(start - 1)
70
-
.take(end - start + 1)
71
-
.collect::<Vec<&str>>()
72
-
.join("\n");
73
74
-
let mut lines_sliced = 0;
75
-
76
-
while content.len() > 1950 {
77
-
let lines = content.lines().collect::<Vec<&str>>();
78
-
if lines.len() == 1 {
79
-
content = content.chars().take(1950).collect();
80
-
break;
81
-
}
82
-
content = lines[..lines.len() - 1].join("\n");
83
-
lines_sliced += 1;
84
-
}
85
-
let end = end - lines_sliced;
86
87
-
let name = format!(
88
-
"{repo}@{} {file} L{start}{}",
89
-
if reference.len() == 40 {
90
-
&reference[..8]
91
-
} else {
92
-
&reference
93
-
},
94
-
if end > start {
95
-
format!("-{end}")
96
-
} else {
97
-
String::new()
98
-
}
99
-
);
100
101
-
let body = if lines_sliced > 0 {
102
-
format!("... ({lines_sliced} lines not displayed)")
103
-
} else {
104
-
String::new()
105
-
};
0
0
106
107
-
code_blocks.push((name, language, content, body));
108
-
}
0
0
0
109
110
-
code_blocks.retain(|(_, _, content, _)| !content.trim().is_empty());
0
111
112
-
if !code_blocks.is_empty() {
113
-
embeds.extend(generic_codeblocks_to_embed(&code_blocks));
114
-
}
0
0
0
0
0
0
115
}
116
-
117
-
Ok(embeds)
118
}
119
120
-
type CodeBlock = (String, String, String, String);
121
-
122
-
fn generic_codeblocks_to_embed(codeblocks: &[CodeBlock]) -> Vec<serenity::CreateEmbed> {
123
-
codeblocks
124
-
.iter()
125
-
.map(|(name, language, content, body)| {
126
-
serenity::CreateEmbed::default()
127
-
.title(name)
128
-
.description(format!("```{language}\n{content}\n```").to_owned())
129
-
.footer(serenity::CreateEmbedFooter::new(body))
130
-
})
131
-
.collect::<Vec<_>>()
132
}
···
1
// the logic here is pretty much ripped from https://github.com/uncenter/discord-forum-bot/blob/main/src/modules/expandGitHubLinks.ts
2
// with some modifications so I can make it work on diffrent git hosts
3
4
+
use color_eyre::eyre::{self, Result};
5
+
use poise::serenity_prelude::{Context, FullEvent};
6
use regex::Regex;
7
use reqwest::Client;
8
9
pub async fn handle(ctx: &Context, event: &FullEvent) -> Result<()> {
10
if let FullEvent::Message { new_message } = event {
11
+
let code_blocks = extract_code_blocks(new_message.content.clone()).await?;
12
13
+
if !code_blocks.is_empty() {
0
0
14
new_message
15
.channel_id
16
+
.say(ctx, code_blocks.join("\n"))
17
.await?;
18
}
19
}
···
21
Ok(())
22
}
23
24
+
async fn extract_code_blocks(msg: String) -> Result<Vec<String>> {
25
let re = Regex::new(
26
+
r"https?://(?P<host>(git.*|codeberg\.org))/(?P<repo>[\w-]+/[\w.-]+)/(blob|(src/(commit|branch)))?/(?P<reference>\S+?)/(?P<file>\S+)#L(?P<start>\d+)(?:[~-]L?(?P<end>\d+)?)?",
27
+
)?;
28
29
+
let mut blocks: Vec<String> = Vec::new();
30
+
let client = Client::new();
31
0
32
for caps in re.captures_iter(&msg) {
33
+
let (host, repo, reference, file, start, end) = extract_url_components(&caps)?;
0
0
0
0
34
35
+
let raw_url = construct_raw_url(host, repo, reference, file);
0
0
0
0
36
37
+
if let Ok(code_block) = fetch_code_block(&client, &raw_url, start, end, file).await {
38
+
blocks.push(code_block);
39
+
}
40
+
}
0
0
0
0
0
0
41
42
+
Ok(blocks)
43
+
}
44
45
+
fn extract_url_components<'a>(
46
+
caps: &'a regex::Captures<'a>,
47
+
) -> Result<(&'a str, &'a str, &'a str, &'a str, usize, usize)> {
48
+
let host = &caps["host"];
49
+
let repo = &caps["repo"];
50
+
let reference = &caps["reference"];
51
+
let file = &caps["file"];
52
+
let start = caps["start"].parse::<usize>()?;
53
+
let end = caps
54
+
.name("end")
55
+
.map_or(Ok(start), |end| end.as_str().parse::<usize>())?;
56
57
+
Ok((host, repo, reference, file, start, end))
58
+
}
0
0
0
0
0
59
60
+
fn construct_raw_url(host: &str, repo: &str, reference: &str, file: &str) -> String {
61
+
if host == "github.com" {
62
+
format!("https://raw.githubusercontent.com/{repo}/{reference}/{file}")
63
+
} else {
64
+
let refer = if reference.len() == 40 {
65
+
format!("commit/{reference}")
66
+
} else {
67
+
format!("branch/{reference}")
68
+
};
69
+
format!("https://{host}/{repo}/raw/{refer}/{file}")
70
+
}
71
+
}
72
73
+
async fn fetch_code_block(
74
+
client: &Client,
75
+
raw_url: &str,
76
+
start: usize,
77
+
end: usize,
78
+
file: &str,
79
+
) -> Result<String> {
80
+
let response = client.get(raw_url).send().await?;
81
+
if !response.status().is_success() {
82
+
return Err(eyre::eyre!("Failed to fetch content from {}", raw_url));
83
+
}
0
0
84
85
+
let text = response.text().await?;
86
+
let content = text
87
+
.lines()
88
+
.skip(start - 1)
89
+
.take(end - start + 1)
90
+
.collect::<Vec<&str>>()
91
+
.join("\n");
92
93
+
let language = file
94
+
.split('.')
95
+
.last()
96
+
.map_or("", remove_query_string)
97
+
.to_lowercase();
98
99
+
Ok(format_code_block(language, content))
100
+
}
101
102
+
fn format_code_block(language: String, content: String) -> String {
103
+
if content.len() > 1950 {
104
+
let truncated_content = content.lines().take(1950).collect::<Vec<&str>>().join("\n");
105
+
format!(
106
+
"```{}\n{}\n```\n... (lines not displayed)",
107
+
language, truncated_content
108
+
)
109
+
} else {
110
+
format!("```{}\n{}\n```", language, content)
111
}
0
0
112
}
113
114
+
fn remove_query_string(input: &str) -> &str {
115
+
input.split('?').next().unwrap_or(input)
0
0
0
0
0
0
0
0
0
0
116
}