merge_whitespace/lib.rs
1//! # merge-whitespace
2//!
3//! This crate contains procedural macros for removing multiple consecutive whitespaces from a
4//! given string literal, replacing them with a single space.
5//!
6//! ## Example
7//!
8//! ```
9//! # use merge_whitespace::merge_whitespace;
10//! const QUERY: &str = merge_whitespace!(r#"
11//! query {
12//! users (limit: 1, filter: "bought a 12\" vinyl
13//! named \"spaces in space \"") {
14//! id
15//! name
16//! todos(order_by: {created_at: desc}, limit: 5) {
17//! id
18//! title
19//! }
20//! }
21//! }
22//! "#,
23//! quote_char = '"',
24//! escape_char = '\\');
25//!
26//! assert_eq!(QUERY, r#"query { users (limit: 1, filter: "bought a 12\" vinyl
27//! named \"spaces in space \"") { id name todos(order_by: {created_at: desc}, limit: 5) { id title } } }"#);
28//! ```
29
30#![forbid(unsafe_code)]
31
32use proc_macro::TokenStream;
33use quote::quote;
34use syn::parse_macro_input;
35
36use crate::macro_input::MacroInput;
37
38mod macro_input;
39
40/// This is a procedural macro that removes multiple consecutive whitespaces from a given string
41/// literal and replaces them with a single space. Quoted text will be ignored and kept as-is.
42///
43/// ## Example
44///
45/// ```
46/// # use merge_whitespace::merge_whitespace;
47/// let output = merge_whitespace!("Hello World!\r\n \"How are\" you?");
48/// assert_eq!(output, r#"Hello World! "How are" you?"#);
49/// ```
50///
51/// If you want to keep quoted text as is, you can specify a quotation mark character.
52/// Everything within a pair of these markers is kept as-is:
53///
54/// ```
55/// # use merge_whitespace::merge_whitespace;
56/// let output = merge_whitespace!("Hello World!\r\n \"How are\" you?", quote_char = '"');
57/// assert_eq!(output, "Hello World! \"How are\" you?");
58/// ```
59///
60/// # Return
61///
62/// The macro expands to the modified string literal.
63#[proc_macro]
64pub fn merge_whitespace(input: TokenStream) -> TokenStream {
65 // Parse the input tokens into a syntax tree
66 let input = parse_macro_input!(input as MacroInput);
67
68 let input_str = input.string.value();
69 let quote_char = input.quote_char;
70 let escape_char = input.escape_char;
71
72 // Replace multiple whitespaces with a single space, skipping quoted blocks
73 let output_str =
74 merge_whitespace_utils::merge_whitespace_with_quotes(&input_str, quote_char, escape_char);
75
76 // Generate the output tokens
77 let output = quote! {
78 #output_str
79 };
80
81 output.into()
82}