feat: escape format specifier(close: #12258)

This commit is contained in:
bvanjoi 2022-05-22 14:40:47 +08:00
parent 3de03d4c61
commit f6b8525b1d
4 changed files with 43 additions and 5 deletions

View file

@ -1,7 +1,7 @@
//! Tools to work with format string literals for the `format_args!` family of macros.
use syntax::{
ast::{self, IsString},
AstNode, AstToken, TextRange,
AstNode, AstToken, TextRange, TextSize,
};
pub fn is_format_string(string: &ast::String) -> bool {
@ -48,6 +48,7 @@ pub enum FormatSpecifier {
Dot,
Asterisk,
QuestionMark,
Escape,
}
pub fn lex_format_specifiers(
@ -66,7 +67,7 @@ pub fn lex_format_specifiers(
// Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
if let Some((_, '{')) = chars.peek() {
// Escaped format specifier, `{{`
chars.next();
read_escaped_format_specifier(&mut chars, &mut callback);
continue;
}
@ -238,6 +239,11 @@ pub fn lex_format_specifiers(
skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
}
continue;
} else if let '}' = first_char {
if let Some((_, '}')) = chars.peek() {
// Escaped format specifier, `}}`
read_escaped_format_specifier(&mut chars, &mut callback);
}
}
}
@ -288,4 +294,15 @@ pub fn lex_format_specifiers(
}
callback(range, FormatSpecifier::Identifier);
}
fn read_escaped_format_specifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
where
I: Iterator<Item = (TextRange, char)>,
F: FnMut(TextRange, FormatSpecifier),
{
let (range, _) = chars.peek().unwrap();
let offset = TextSize::from(1);
callback(TextRange::new(range.start() - offset, range.end()), FormatSpecifier::Escape);
chars.next();
}
}