aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/lib.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-10 20:33:29 +0100
committerAleksey Kladov <[email protected]>2018-08-10 20:33:29 +0100
commit7c67612b8a894187fa3b64725531a5459f9211bf (patch)
tree9e2a536efa0c880d921fd8d4d74423afc9451fd4 /crates/libeditor/src/lib.rs
parent26262aaf05983c5b7f41cc438e287523268fe1eb (diff)
organizize
Diffstat (limited to 'crates/libeditor/src/lib.rs')
-rw-r--r--crates/libeditor/src/lib.rs155
1 files changed, 155 insertions, 0 deletions
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
new file mode 100644
index 000000000..f77647338
--- /dev/null
+++ b/crates/libeditor/src/lib.rs
@@ -0,0 +1,155 @@
1extern crate libsyntax2;
2extern crate superslice;
3
4mod extend_selection;
5mod line_index;
6
7use libsyntax2::{
8 SyntaxNodeRef, AstNode,
9 algo::walk,
10 SyntaxKind::*,
11};
12pub use libsyntax2::{TextRange, TextUnit, ast};
13pub use self::line_index::{LineIndex, LineCol};
14
15#[derive(Debug)]
16pub struct HighlightedRange {
17 pub range: TextRange,
18 pub tag: &'static str,
19}
20
21#[derive(Debug)]
22pub struct Diagnostic {
23 pub range: TextRange,
24 pub msg: String,
25}
26
27#[derive(Debug)]
28pub struct Symbol {
29 // pub parent: ???,
30 pub name: String,
31 pub range: TextRange,
32}
33
34#[derive(Debug)]
35pub struct Runnable {
36 pub range: TextRange,
37 pub kind: RunnableKind,
38}
39
40#[derive(Debug)]
41pub enum RunnableKind {
42 Test { name: String },
43 Bin,
44}
45
46pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
47 let syntax = file.syntax();
48 let mut res = Vec::new();
49 for node in walk::preorder(syntax.as_ref()) {
50 let tag = match node.kind() {
51 ERROR => "error",
52 COMMENT | DOC_COMMENT => "comment",
53 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
54 ATTR => "attribute",
55 NAME_REF => "text",
56 NAME => "function",
57 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
58 LIFETIME => "parameter",
59 k if k.is_keyword() => "keyword",
60 _ => continue,
61 };
62 res.push(HighlightedRange {
63 range: node.range(),
64 tag,
65 })
66 }
67 res
68}
69
70pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> {
71 let syntax = file.syntax();
72 let mut res = Vec::new();
73
74 for node in walk::preorder(syntax.as_ref()) {
75 if node.kind() == ERROR {
76 res.push(Diagnostic {
77 range: node.range(),
78 msg: "Syntax Error".to_string(),
79 });
80 }
81 }
82 res.extend(file.errors().into_iter().map(|err| Diagnostic {
83 range: TextRange::offset_len(err.offset, 1.into()),
84 msg: err.msg,
85 }));
86 res
87}
88
89pub fn syntax_tree(file: &ast::File) -> String {
90 ::libsyntax2::utils::dump_tree(&file.syntax())
91}
92
93pub fn symbols(file: &ast::File) -> Vec<Symbol> {
94 let syntax = file.syntax();
95 let res: Vec<Symbol> = walk::preorder(syntax.as_ref())
96 .filter_map(Declaration::cast)
97 .filter_map(|decl| {
98 let name = decl.name()?;
99 let range = decl.range();
100 Some(Symbol { name, range })
101 })
102 .collect();
103 res // NLL :-(
104}
105
106pub fn extend_selection(file: &ast::File, range: TextRange) -> Option<TextRange> {
107 let syntax = file.syntax();
108 extend_selection::extend_selection(syntax.as_ref(), range)
109}
110
111pub fn runnables(file: &ast::File) -> Vec<Runnable> {
112 file
113 .functions()
114 .filter_map(|f| {
115 let name = f.name()?.text();
116 let kind = if name == "main" {
117 RunnableKind::Bin
118 } else if f.has_atom_attr("test") {
119 RunnableKind::Test {
120 name: name.to_string()
121 }
122 } else {
123 return None;
124 };
125 Some(Runnable {
126 range: f.syntax().range(),
127 kind,
128 })
129 })
130 .collect()
131}
132
133
134struct Declaration<'f> (SyntaxNodeRef<'f>);
135
136impl<'f> Declaration<'f> {
137 fn cast(node: SyntaxNodeRef<'f>) -> Option<Declaration<'f>> {
138 match node.kind() {
139 | STRUCT_ITEM | ENUM_ITEM | FUNCTION | TRAIT_ITEM
140 | CONST_ITEM | STATIC_ITEM | MOD_ITEM | NAMED_FIELD
141 | TYPE_ITEM => Some(Declaration(node)),
142 _ => None
143 }
144 }
145
146 fn name(&self) -> Option<String> {
147 let name = self.0.children()
148 .find(|child| child.kind() == NAME)?;
149 Some(name.text())
150 }
151
152 fn range(&self) -> TextRange {
153 self.0.range()
154 }
155}