aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api_light/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api_light/src/lib.rs')
-rw-r--r--crates/ra_ide_api_light/src/lib.rs168
1 files changed, 168 insertions, 0 deletions
diff --git a/crates/ra_ide_api_light/src/lib.rs b/crates/ra_ide_api_light/src/lib.rs
new file mode 100644
index 000000000..5a6af19b7
--- /dev/null
+++ b/crates/ra_ide_api_light/src/lib.rs
@@ -0,0 +1,168 @@
1pub mod assists;
2mod extend_selection;
3mod folding_ranges;
4mod line_index;
5mod line_index_utils;
6mod structure;
7#[cfg(test)]
8mod test_utils;
9mod typing;
10mod diagnostics;
11
12pub use self::{
13 assists::LocalEdit,
14 extend_selection::extend_selection,
15 folding_ranges::{folding_ranges, Fold, FoldKind},
16 line_index::{LineCol, LineIndex},
17 line_index_utils::translate_offset_with_edit,
18 structure::{file_structure, StructureNode},
19 typing::{join_lines, on_enter, on_dot_typed, on_eq_typed},
20 diagnostics::diagnostics
21};
22use ra_text_edit::TextEditBuilder;
23use ra_syntax::{
24 SourceFile, SyntaxNode, TextRange, TextUnit, Direction,
25 SyntaxKind::{self, *},
26 ast::{self, AstNode},
27 algo::find_leaf_at_offset,
28};
29use rustc_hash::FxHashSet;
30
31#[derive(Debug)]
32pub struct HighlightedRange {
33 pub range: TextRange,
34 pub tag: &'static str,
35}
36
37#[derive(Debug, Copy, Clone)]
38pub enum Severity {
39 Error,
40 WeakWarning,
41}
42
43#[derive(Debug)]
44pub struct Diagnostic {
45 pub range: TextRange,
46 pub msg: String,
47 pub severity: Severity,
48 pub fix: Option<LocalEdit>,
49}
50
51pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> {
52 const BRACES: &[SyntaxKind] = &[
53 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
54 ];
55 let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset)
56 .filter_map(|node| {
57 let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
58 Some((node, idx))
59 })
60 .next()?;
61 let parent = brace_node.parent()?;
62 let matching_kind = BRACES[brace_idx ^ 1];
63 let matching_node = parent
64 .children()
65 .find(|node| node.kind() == matching_kind)?;
66 Some(matching_node.range().start())
67}
68
69pub fn highlight(root: &SyntaxNode) -> Vec<HighlightedRange> {
70 // Visited nodes to handle highlighting priorities
71 let mut highlighted = FxHashSet::default();
72 let mut res = Vec::new();
73 for node in root.descendants() {
74 if highlighted.contains(&node) {
75 continue;
76 }
77 let tag = match node.kind() {
78 COMMENT => "comment",
79 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
80 ATTR => "attribute",
81 NAME_REF => "text",
82 NAME => "function",
83 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
84 LIFETIME => "parameter",
85 k if k.is_keyword() => "keyword",
86 _ => {
87 if let Some(macro_call) = ast::MacroCall::cast(node) {
88 if let Some(path) = macro_call.path() {
89 if let Some(segment) = path.segment() {
90 if let Some(name_ref) = segment.name_ref() {
91 highlighted.insert(name_ref.syntax());
92 let range_start = name_ref.syntax().range().start();
93 let mut range_end = name_ref.syntax().range().end();
94 for sibling in path.syntax().siblings(Direction::Next) {
95 match sibling.kind() {
96 EXCL | IDENT => range_end = sibling.range().end(),
97 _ => (),
98 }
99 }
100 res.push(HighlightedRange {
101 range: TextRange::from_to(range_start, range_end),
102 tag: "macro",
103 })
104 }
105 }
106 }
107 }
108 continue;
109 }
110 };
111 res.push(HighlightedRange {
112 range: node.range(),
113 tag,
114 })
115 }
116 res
117}
118
119pub fn syntax_tree(file: &SourceFile) -> String {
120 ::ra_syntax::utils::dump_tree(file.syntax())
121}
122
123#[cfg(test)]
124mod tests {
125 use ra_syntax::AstNode;
126
127 use crate::test_utils::{add_cursor, assert_eq_dbg, assert_eq_text, extract_offset};
128
129 use super::*;
130
131 #[test]
132 fn test_highlighting() {
133 let file = SourceFile::parse(
134 r#"
135// comment
136fn main() {}
137 println!("Hello, {}!", 92);
138"#,
139 );
140 let hls = highlight(file.syntax());
141 assert_eq_dbg(
142 r#"[HighlightedRange { range: [1; 11), tag: "comment" },
143 HighlightedRange { range: [12; 14), tag: "keyword" },
144 HighlightedRange { range: [15; 19), tag: "function" },
145 HighlightedRange { range: [29; 37), tag: "macro" },
146 HighlightedRange { range: [38; 50), tag: "string" },
147 HighlightedRange { range: [52; 54), tag: "literal" }]"#,
148 &hls,
149 );
150 }
151
152 #[test]
153 fn test_matching_brace() {
154 fn do_check(before: &str, after: &str) {
155 let (pos, before) = extract_offset(before);
156 let file = SourceFile::parse(&before);
157 let new_pos = match matching_brace(&file, pos) {
158 None => pos,
159 Some(pos) => pos,
160 };
161 let actual = add_cursor(&before, new_pos);
162 assert_eq_text!(after, &actual);
163 }
164
165 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }");
166 }
167
168}