diff options
author | Aleksey Kladov <[email protected]> | 2018-08-10 13:07:43 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-10 13:07:43 +0100 |
commit | d7c5a6f3081c2e7266620779d3c32067f947b959 (patch) | |
tree | 2aefb594e062c8fa7cc7879e5df6883f3bc5d015 /libeditor | |
parent | 4a900fd6815d3ea722b5e664aee9eac8bb9cb14f (diff) |
Start lang server
Diffstat (limited to 'libeditor')
-rw-r--r-- | libeditor/src/lib.rs | 165 |
1 files changed, 77 insertions, 88 deletions
diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index 5ebb49139..817a2d15b 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs | |||
@@ -6,13 +6,10 @@ use libsyntax2::{ | |||
6 | SyntaxNodeRef, AstNode, | 6 | SyntaxNodeRef, AstNode, |
7 | algo::walk, | 7 | algo::walk, |
8 | SyntaxKind::*, | 8 | SyntaxKind::*, |
9 | ast, | ||
9 | }; | 10 | }; |
10 | pub use libsyntax2::{TextRange, TextUnit}; | 11 | pub use libsyntax2::{TextRange, TextUnit}; |
11 | 12 | ||
12 | pub struct File { | ||
13 | inner: libsyntax2::File | ||
14 | } | ||
15 | |||
16 | #[derive(Debug)] | 13 | #[derive(Debug)] |
17 | pub struct HighlightedRange { | 14 | pub struct HighlightedRange { |
18 | pub range: TextRange, | 15 | pub range: TextRange, |
@@ -44,103 +41,95 @@ pub enum RunnableKind { | |||
44 | Bin, | 41 | Bin, |
45 | } | 42 | } |
46 | 43 | ||
47 | impl File { | 44 | pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> { |
48 | pub fn new(text: &str) -> File { | 45 | let syntax = file.syntax(); |
49 | File { | 46 | let mut res = Vec::new(); |
50 | inner: libsyntax2::File::parse(text) | 47 | for node in walk::preorder(syntax.as_ref()) { |
51 | } | 48 | let tag = match node.kind() { |
49 | ERROR => "error", | ||
50 | COMMENT | DOC_COMMENT => "comment", | ||
51 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", | ||
52 | ATTR => "attribute", | ||
53 | NAME_REF => "text", | ||
54 | NAME => "function", | ||
55 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", | ||
56 | LIFETIME => "parameter", | ||
57 | k if k.is_keyword() => "keyword", | ||
58 | _ => continue, | ||
59 | }; | ||
60 | res.push(HighlightedRange { | ||
61 | range: node.range(), | ||
62 | tag, | ||
63 | }) | ||
52 | } | 64 | } |
65 | res | ||
66 | } | ||
53 | 67 | ||
54 | pub fn highlight(&self) -> Vec<HighlightedRange> { | 68 | pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> { |
55 | let syntax = self.inner.syntax(); | 69 | let syntax = file.syntax(); |
56 | let mut res = Vec::new(); | 70 | let mut res = Vec::new(); |
57 | for node in walk::preorder(syntax.as_ref()) { | ||
58 | let tag = match node.kind() { | ||
59 | ERROR => "error", | ||
60 | COMMENT | DOC_COMMENT => "comment", | ||
61 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", | ||
62 | ATTR => "attribute", | ||
63 | NAME_REF => "text", | ||
64 | NAME => "function", | ||
65 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", | ||
66 | LIFETIME => "parameter", | ||
67 | k if k.is_keyword() => "keyword", | ||
68 | _ => continue, | ||
69 | }; | ||
70 | res.push(HighlightedRange { | ||
71 | range: node.range(), | ||
72 | tag, | ||
73 | }) | ||
74 | } | ||
75 | res | ||
76 | } | ||
77 | 71 | ||
78 | pub fn diagnostics(&self) -> Vec<Diagnostic> { | 72 | for node in walk::preorder(syntax.as_ref()) { |
79 | let syntax = self.inner.syntax(); | 73 | if node.kind() == ERROR { |
80 | let mut res = Vec::new(); | 74 | res.push(Diagnostic { |
81 | 75 | range: node.range(), | |
82 | for node in walk::preorder(syntax.as_ref()) { | 76 | msg: "Syntax Error".to_string(), |
83 | if node.kind() == ERROR { | 77 | }); |
84 | res.push(Diagnostic { | ||
85 | range: node.range(), | ||
86 | msg: "Syntax Error".to_string(), | ||
87 | }); | ||
88 | } | ||
89 | } | 78 | } |
90 | res.extend(self.inner.errors().into_iter().map(|err| Diagnostic { | ||
91 | range: TextRange::offset_len(err.offset, 1.into()), | ||
92 | msg: err.msg, | ||
93 | })); | ||
94 | res | ||
95 | } | 79 | } |
80 | res.extend(file.errors().into_iter().map(|err| Diagnostic { | ||
81 | range: TextRange::offset_len(err.offset, 1.into()), | ||
82 | msg: err.msg, | ||
83 | })); | ||
84 | res | ||
85 | } | ||
96 | 86 | ||
97 | pub fn syntax_tree(&self) -> String { | 87 | pub fn syntax_tree(file: &ast::File) -> String { |
98 | ::libsyntax2::utils::dump_tree(&self.inner.syntax()) | 88 | ::libsyntax2::utils::dump_tree(&file.syntax()) |
99 | } | 89 | } |
100 | 90 | ||
101 | pub fn symbols(&self) -> Vec<Symbol> { | 91 | pub fn symbols(file: &ast::File) -> Vec<Symbol> { |
102 | let syntax = self.inner.syntax(); | 92 | let syntax = file.syntax(); |
103 | let res: Vec<Symbol> = walk::preorder(syntax.as_ref()) | 93 | let res: Vec<Symbol> = walk::preorder(syntax.as_ref()) |
104 | .filter_map(Declaration::cast) | 94 | .filter_map(Declaration::cast) |
105 | .filter_map(|decl| { | 95 | .filter_map(|decl| { |
106 | let name = decl.name()?; | 96 | let name = decl.name()?; |
107 | let range = decl.range(); | 97 | let range = decl.range(); |
108 | Some(Symbol { name, range }) | 98 | Some(Symbol { name, range }) |
109 | }) | 99 | }) |
110 | .collect(); | 100 | .collect(); |
111 | res // NLL :-( | 101 | res // NLL :-( |
112 | } | 102 | } |
113 | 103 | ||
114 | pub fn extend_selection(&self, range: TextRange) -> Option<TextRange> { | 104 | pub fn extend_selection(file: &ast::File, range: TextRange) -> Option<TextRange> { |
115 | let syntax = self.inner.syntax(); | 105 | let syntax = file.syntax(); |
116 | extend_selection::extend_selection(syntax.as_ref(), range) | 106 | extend_selection::extend_selection(syntax.as_ref(), range) |
117 | } | 107 | } |
118 | 108 | ||
119 | pub fn runnables(&self) -> Vec<Runnable> { | 109 | pub fn runnables(file: &ast::File) -> Vec<Runnable> { |
120 | self.inner | 110 | file |
121 | .functions() | 111 | .functions() |
122 | .filter_map(|f| { | 112 | .filter_map(|f| { |
123 | let name = f.name()?.text(); | 113 | let name = f.name()?.text(); |
124 | let kind = if name == "main" { | 114 | let kind = if name == "main" { |
125 | RunnableKind::Bin | 115 | RunnableKind::Bin |
126 | } else if f.has_atom_attr("test") { | 116 | } else if f.has_atom_attr("test") { |
127 | RunnableKind::Test { | 117 | RunnableKind::Test { |
128 | name: name.to_string() | 118 | name: name.to_string() |
129 | } | 119 | } |
130 | } else { | 120 | } else { |
131 | return None; | 121 | return None; |
132 | }; | 122 | }; |
133 | Some(Runnable { | 123 | Some(Runnable { |
134 | range: f.syntax().range(), | 124 | range: f.syntax().range(), |
135 | kind, | 125 | kind, |
136 | }) | ||
137 | }) | 126 | }) |
138 | .collect() | 127 | }) |
139 | } | 128 | .collect() |
140 | } | 129 | } |
141 | 130 | ||
142 | 131 | ||
143 | struct Declaration<'f>(SyntaxNodeRef<'f>); | 132 | struct Declaration<'f> (SyntaxNodeRef<'f>); |
144 | 133 | ||
145 | impl<'f> Declaration<'f> { | 134 | impl<'f> Declaration<'f> { |
146 | fn cast(node: SyntaxNodeRef<'f>) -> Option<Declaration<'f>> { | 135 | fn cast(node: SyntaxNodeRef<'f>) -> Option<Declaration<'f>> { |