mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-27 09:12:35 +01:00
Telegram markdown support for structured json messages
This commit is contained in:
@@ -3,6 +3,7 @@ use std::io::{self, Read};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize};
|
||||
use serde_json::{self, Deserializer, Value};
|
||||
use crate::utils::humanize_snake_case;
|
||||
|
||||
fn read_skipping_ws(mut reader: impl Read) -> io::Result<u8> {
|
||||
loop {
|
||||
@@ -166,4 +167,52 @@ where
|
||||
{
|
||||
let value: Option<String> = Option::deserialize(deserializer)?;
|
||||
Ok(value.unwrap_or_default())
|
||||
}
|
||||
|
||||
const MARKDOWN_SPECIAL_CHARS: &str = r#"_*[]()~`>#+-=|{}.!\"#;
|
||||
|
||||
fn escape_markdown_v2(text: &str) -> String {
|
||||
let mut escaped = String::new();
|
||||
for c in text.chars() {
|
||||
if MARKDOWN_SPECIAL_CHARS.contains(c) {
|
||||
escaped.push('\\');
|
||||
}
|
||||
escaped.push(c);
|
||||
}
|
||||
escaped
|
||||
}
|
||||
|
||||
fn json_to_markdown(value: &Value) -> String {
|
||||
fn format_value(v: &Value, indent: usize) -> String {
|
||||
let pad = " ".repeat(indent);
|
||||
match v {
|
||||
Value::Object(map) => map.iter()
|
||||
.map(|(k, v)| {
|
||||
let formatted = format_value(v, indent + 1);
|
||||
let key = humanize_snake_case(k);
|
||||
if v.is_object() || v.is_array() {
|
||||
format!("{pad}*{key}:*\n{formatted}")
|
||||
} else {
|
||||
format!("{pad}*{key}:* {formatted}")
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
Value::Array(arr) => arr.iter()
|
||||
.map(|v| format!("{pad}\\- {}", format_value(v, indent + 1).trim()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
Value::String(s) => escape_markdown_v2(s),
|
||||
Value::Number(n) => escape_markdown_v2(&n.to_string()),
|
||||
Value::Bool(b) => b.to_string(),
|
||||
Value::Null => "null".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
format_value(value, 0)
|
||||
}
|
||||
|
||||
pub fn json_str_to_markdown(json_str: &str) -> Result<String, serde_json::Error> {
|
||||
let value: Value = serde_json::from_str(json_str)?;
|
||||
Ok(json_to_markdown(&value))
|
||||
}
|
||||
@@ -106,6 +106,27 @@ pub fn mask_credentials(s: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn humanize_snake_case(s: &str) -> String {
|
||||
let mut result = String::with_capacity(s.len());
|
||||
let mut capitalize_next = true;
|
||||
|
||||
for c in s.chars() {
|
||||
if c == '_' {
|
||||
result.push(' ');
|
||||
capitalize_next = true;
|
||||
} else if capitalize_next {
|
||||
for up in c.to_uppercase() {
|
||||
result.push(up);
|
||||
}
|
||||
capitalize_next = false;
|
||||
} else {
|
||||
result.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::collections::HashSet;
|
||||
|
||||
Reference in New Issue
Block a user