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}