From 7ff85d7fdb405d2bb67b3b51898a258df6904803 Mon Sep 17 00:00:00 2001 From: Shagnor Date: Sat, 24 Dec 2022 01:34:01 +1100 Subject: [PATCH] Add ansi! macro --- Cargo.lock | 34 +++++++++++++-- ansi_macro/Cargo.toml | 12 ++++++ ansi_macro/src/lib.rs | 62 ++++++++++++++++++++++++++++ blastmud_game/Cargo.toml | 1 + blastmud_game/src/message_handler.rs | 3 +- 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 ansi_macro/Cargo.toml create mode 100644 ansi_macro/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 5060e90..da73674 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ansi_macro" +version = "0.1.0" +dependencies = [ + "nom", + "quote", + "syn", +] + [[package]] name = "async-trait" version = "0.1.59" @@ -52,6 +61,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" name = "blastmud_game" version = "0.1.0" dependencies = [ + "ansi_macro", "base64 0.20.0", "blastmud_interfaces", "deadpool", @@ -637,6 +647,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "0.8.5" @@ -681,6 +697,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -868,9 +894,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1174,9 +1200,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", diff --git a/ansi_macro/Cargo.toml b/ansi_macro/Cargo.toml new file mode 100644 index 0000000..0d06eba --- /dev/null +++ b/ansi_macro/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ansi_macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +nom = "7.1.1" +quote = "1.0.23" +syn = "1.0.107" diff --git a/ansi_macro/src/lib.rs b/ansi_macro/src/lib.rs new file mode 100644 index 0000000..13dddce --- /dev/null +++ b/ansi_macro/src/lib.rs @@ -0,0 +1,62 @@ +use proc_macro::TokenStream; +use syn::{parse_macro_input, Lit}; +use quote::ToTokens; +use nom::{ + combinator::eof, + branch::alt, multi::fold_many0, + bytes::complete::{take_till, take_till1, tag}, + sequence::{tuple, pair}, + error::Error, + Err, + Parser +}; + +enum AnsiFrag<'l> { + Lit(&'l str), + Special(&'l str) +} +use AnsiFrag::Special; + +#[proc_macro] +pub fn ansi(input: TokenStream) -> TokenStream { + let raw = match parse_macro_input!(input as Lit) { + Lit::Str(lit_str) => lit_str.value(), + _ => panic!("Expected a string literal") + }; + fn parser(i: &str) -> Result>> { + pair(fold_many0( + alt(( + take_till1(|c| c == '<').map(AnsiFrag::Lit), + tuple((tag("<"), take_till(|c| c == '>'), tag(">"))).map(|t| AnsiFrag::Special(t.1)) + )), + || "".to_owned(), + |a, r| a + match r { + AnsiFrag::Lit(s) => &s, + Special(s) if s == "reset" => "\x1b[0m", + Special(s) if s == "bold" => "\x1b[1m", + Special(s) if s == "under" => "\x1b[4m", + Special(s) if s == "strike" => "\x1b[9m", + Special(s) if s == "black" => "\x1b[30m", + Special(s) if s == "red" => "\x1b[31m", + Special(s) if s == "green" => "\x1b[32m", + Special(s) if s == "yellow" => "\x1b[33m", + Special(s) if s == "blue" => "\x1b[34m", + Special(s) if s == "magenta" => "\x1b[35m", + Special(s) if s == "cyan" => "\x1b[36m", + Special(s) if s == "white" => "\x1b[37m", + Special(s) if s == "bgblack" => "\x1b[40m", + Special(s) if s == "bgred" => "\x1b[41m", + Special(s) if s == "bggreen" => "\x1b[42m", + Special(s) if s == "bgyellow" => "\x1b[43m", + Special(s) if s == "bgblue" => "\x1b[44m", + Special(s) if s == "bgmagenta" => "\x1b[45m", + Special(s) if s == "bgcyan" => "\x1b[46m", + Special(s) if s == "bgwhite" => "\x1b[47m", + Special(r) => panic!("Unknown ansi type {}", r) + } + ), eof)(i).map(|(_, (r, _))| r) + } + TokenStream::from(parser(&raw) + .unwrap_or_else(|e| { panic!("Bad ansi literal: {}", e) }) + .into_token_stream()) +} diff --git a/blastmud_game/Cargo.toml b/blastmud_game/Cargo.toml index 5fd0207..26f7778 100644 --- a/blastmud_game/Cargo.toml +++ b/blastmud_game/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] base64 = "0.20.0" blastmud_interfaces = { path = "../blastmud_interfaces" } +ansi_macro = { path = "../ansi_macro" } deadpool = "0.9.5" deadpool-postgres = { version = "0.10.3", features = ["serde"] } futures = "0.3.25" diff --git a/blastmud_game/src/message_handler.rs b/blastmud_game/src/message_handler.rs index 6b949d8..eb32559 100644 --- a/blastmud_game/src/message_handler.rs +++ b/blastmud_game/src/message_handler.rs @@ -3,6 +3,7 @@ use crate::db; use MessageFromListener::*; use uuid::Uuid; use crate::DResult; +use ansi_macro::ansi; #[derive(Clone,Debug)] pub struct ListenerSession { @@ -22,7 +23,7 @@ pub async fn handle(listener: Uuid, msg: MessageFromListener, pool: db::DBPool) } SessionSentLine { session, msg } => { pool.queue_for_session(&ListenerSession { listener, session }, - &format!("You hear an echo saying: \x1b[31m{}\x1b[0m\r\n", msg)).await?; + &format!(ansi!("You hear an echo saying: {}\r\n"), msg)).await?; } AcknowledgeMessage => {} }