aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs81
1 files changed, 75 insertions, 6 deletions
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index fdd87bcff..a0c5e78ad 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -1,12 +1,81 @@
1use ra_syntax::AstNode; 1use rustc_hash::FxHashSet;
2
3use ra_syntax::{ast, AstNode, TextRange, Direction, SyntaxKind::*};
2use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
3 5
4use crate::{ 6use crate::{FileId, db::RootDatabase};
5 FileId, HighlightedRange, 7
6 db::RootDatabase, 8#[derive(Debug)]
7}; 9pub struct HighlightedRange {
10 pub range: TextRange,
11 pub tag: &'static str,
12}
8 13
9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { 14pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
10 let source_file = db.parse(file_id); 15 let source_file = db.parse(file_id);
11 ra_ide_api_light::highlight(source_file.syntax()) 16
17 // Visited nodes to handle highlighting priorities
18 let mut highlighted = FxHashSet::default();
19 let mut res = Vec::new();
20 for node in source_file.syntax().descendants() {
21 if highlighted.contains(&node) {
22 continue;
23 }
24 let tag = match node.kind() {
25 COMMENT => "comment",
26 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
27 ATTR => "attribute",
28 NAME_REF => "text",
29 NAME => "function",
30 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
31 LIFETIME => "parameter",
32 k if k.is_keyword() => "keyword",
33 _ => {
34 if let Some(macro_call) = ast::MacroCall::cast(node) {
35 if let Some(path) = macro_call.path() {
36 if let Some(segment) = path.segment() {
37 if let Some(name_ref) = segment.name_ref() {
38 highlighted.insert(name_ref.syntax());
39 let range_start = name_ref.syntax().range().start();
40 let mut range_end = name_ref.syntax().range().end();
41 for sibling in path.syntax().siblings(Direction::Next) {
42 match sibling.kind() {
43 EXCL | IDENT => range_end = sibling.range().end(),
44 _ => (),
45 }
46 }
47 res.push(HighlightedRange {
48 range: TextRange::from_to(range_start, range_end),
49 tag: "macro",
50 })
51 }
52 }
53 }
54 }
55 continue;
56 }
57 };
58 res.push(HighlightedRange { range: node.range(), tag })
59 }
60 res
61}
62
63#[cfg(test)]
64mod tests {
65 use insta::assert_debug_snapshot_matches;
66
67 use crate::mock_analysis::single_file;
68
69 #[test]
70 fn test_highlighting() {
71 let (analysis, file_id) = single_file(
72 r#"
73// comment
74fn main() {}
75 println!("Hello, {}!", 92);
76"#,
77 );
78 let result = analysis.highlight(file_id);
79 assert_debug_snapshot_matches!("highlighting", result);
80 }
12} 81}