]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/syntax_highlighting/format.rs
Merge #8048
[rust.git] / crates / ide / src / syntax_highlighting / format.rs
1 //! Syntax highlighting for format macro strings.
2 use ide_db::SymbolKind;
3 use syntax::{
4     ast::{self, FormatSpecifier, HasFormatSpecifier},
5     AstNode, AstToken, TextRange,
6 };
7
8 use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag};
9
10 pub(super) fn highlight_format_string(
11     stack: &mut Highlights,
12     string: &ast::String,
13     range: TextRange,
14 ) {
15     if is_format_string(string).is_none() {
16         return;
17     }
18
19     string.lex_format_specifier(|piece_range, kind| {
20         if let Some(highlight) = highlight_format_specifier(kind) {
21             stack.add(HlRange {
22                 range: piece_range + range.start(),
23                 highlight: highlight.into(),
24                 binding_hash: None,
25             });
26         }
27     });
28 }
29
30 fn is_format_string(string: &ast::String) -> Option<()> {
31     let parent = string.syntax().parent()?;
32
33     let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?;
34     if !matches!(name.text(), "format_args" | "format_args_nl") {
35         return None;
36     }
37
38     let first_literal = parent
39         .children_with_tokens()
40         .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast))
41         .next()?;
42     if &first_literal != string {
43         return None;
44     }
45
46     Some(())
47 }
48
49 fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
50     Some(match kind {
51         FormatSpecifier::Open
52         | FormatSpecifier::Close
53         | FormatSpecifier::Colon
54         | FormatSpecifier::Fill
55         | FormatSpecifier::Align
56         | FormatSpecifier::Sign
57         | FormatSpecifier::NumberSign
58         | FormatSpecifier::DollarSign
59         | FormatSpecifier::Dot
60         | FormatSpecifier::Asterisk
61         | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier,
62
63         FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral,
64
65         FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local),
66     })
67 }