diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-11 12:49:09 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-11 12:49:09 +0000 |
commit | 0f4bc7589c40732fb78cb59525a6b4dcfb515567 (patch) | |
tree | 4ff25038c52dc1767579135bb5387b0fb184c83d /crates | |
parent | dd122145b57513cf57076ae3235d70215b226039 (diff) | |
parent | a1b661faec69e5c643924bf672ac61ff4ff12202 (diff) |
Merge #495
495: Fix on type handlers r=matklad a=matklad
Looks like our on type handlers didn't actually worked, this shoud fix that!
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide_api_light/src/assists.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide_api_light/src/formatting.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide_api_light/src/typing.rs | 284 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 47 |
4 files changed, 174 insertions, 178 deletions
diff --git a/crates/ra_ide_api_light/src/assists.rs b/crates/ra_ide_api_light/src/assists.rs index 83eabfc85..3495ad967 100644 --- a/crates/ra_ide_api_light/src/assists.rs +++ b/crates/ra_ide_api_light/src/assists.rs | |||
@@ -15,10 +15,11 @@ use ra_text_edit::{TextEdit, TextEditBuilder}; | |||
15 | use ra_syntax::{ | 15 | use ra_syntax::{ |
16 | Direction, SyntaxNode, TextUnit, TextRange, SourceFile, AstNode, | 16 | Direction, SyntaxNode, TextUnit, TextRange, SourceFile, AstNode, |
17 | algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, | 17 | algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, |
18 | ast::{self, AstToken}, | ||
19 | }; | 18 | }; |
20 | use itertools::Itertools; | 19 | use itertools::Itertools; |
21 | 20 | ||
21 | use crate::formatting::leading_indent; | ||
22 | |||
22 | pub use self::{ | 23 | pub use self::{ |
23 | flip_comma::flip_comma, | 24 | flip_comma::flip_comma, |
24 | add_derive::add_derive, | 25 | add_derive::add_derive, |
@@ -165,7 +166,7 @@ impl AssistBuilder { | |||
165 | } | 166 | } |
166 | fn replace_node_and_indent(&mut self, node: &SyntaxNode, replace_with: impl Into<String>) { | 167 | fn replace_node_and_indent(&mut self, node: &SyntaxNode, replace_with: impl Into<String>) { |
167 | let mut replace_with = replace_with.into(); | 168 | let mut replace_with = replace_with.into(); |
168 | if let Some(indent) = calc_indent(node) { | 169 | if let Some(indent) = leading_indent(node) { |
169 | replace_with = reindent(&replace_with, indent) | 170 | replace_with = reindent(&replace_with, indent) |
170 | } | 171 | } |
171 | self.replace(node.range(), replace_with) | 172 | self.replace(node.range(), replace_with) |
@@ -182,12 +183,6 @@ impl AssistBuilder { | |||
182 | } | 183 | } |
183 | } | 184 | } |
184 | 185 | ||
185 | fn calc_indent(node: &SyntaxNode) -> Option<&str> { | ||
186 | let prev = node.prev_sibling()?; | ||
187 | let ws_text = ast::Whitespace::cast(prev)?.text(); | ||
188 | ws_text.rfind('\n').map(|pos| &ws_text[pos + 1..]) | ||
189 | } | ||
190 | |||
191 | fn reindent(text: &str, indent: &str) -> String { | 186 | fn reindent(text: &str, indent: &str) -> String { |
192 | let indent = format!("\n{}", indent); | 187 | let indent = format!("\n{}", indent); |
193 | text.lines().intersperse(&indent).collect() | 188 | text.lines().intersperse(&indent).collect() |
diff --git a/crates/ra_ide_api_light/src/formatting.rs b/crates/ra_ide_api_light/src/formatting.rs index 1f3769209..4635fbd60 100644 --- a/crates/ra_ide_api_light/src/formatting.rs +++ b/crates/ra_ide_api_light/src/formatting.rs | |||
@@ -1,8 +1,16 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast, AstNode, | 2 | AstNode, |
3 | SyntaxNode, SyntaxKind::*, | 3 | SyntaxNode, SyntaxKind::*, |
4 | ast::{self, AstToken}, | ||
4 | }; | 5 | }; |
5 | 6 | ||
7 | /// If the node is on the begining of the line, calculate indent. | ||
8 | pub(crate) fn leading_indent(node: &SyntaxNode) -> Option<&str> { | ||
9 | let prev = node.prev_sibling()?; | ||
10 | let ws_text = ast::Whitespace::cast(prev)?.text(); | ||
11 | ws_text.rfind('\n').map(|pos| &ws_text[pos + 1..]) | ||
12 | } | ||
13 | |||
6 | pub(crate) fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { | 14 | pub(crate) fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { |
7 | let expr = block.expr()?; | 15 | let expr = block.expr()?; |
8 | if expr.syntax().text().contains('\n') { | 16 | if expr.syntax().text().contains('\n') { |
diff --git a/crates/ra_ide_api_light/src/typing.rs b/crates/ra_ide_api_light/src/typing.rs index 5726209cc..c8f3dfe44 100644 --- a/crates/ra_ide_api_light/src/typing.rs +++ b/crates/ra_ide_api_light/src/typing.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | AstNode, SourceFile, SyntaxKind::*, | ||
3 | SyntaxNode, TextUnit, TextRange, | ||
2 | algo::{find_node_at_offset, find_leaf_at_offset, LeafAtOffset}, | 4 | algo::{find_node_at_offset, find_leaf_at_offset, LeafAtOffset}, |
3 | ast, | 5 | ast::{self, AstToken}, |
4 | AstNode, Direction, SourceFile, SyntaxKind::*, | ||
5 | SyntaxNode, TextUnit, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{LocalEdit, TextEditBuilder}; | 8 | use crate::{LocalEdit, TextEditBuilder, formatting::leading_indent}; |
9 | 9 | ||
10 | pub fn on_enter(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { | 10 | pub fn on_enter(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { |
11 | let comment = find_leaf_at_offset(file.syntax(), offset) | 11 | let comment = find_leaf_at_offset(file.syntax(), offset) |
@@ -53,20 +53,21 @@ fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> { | |||
53 | Some(&text[pos..]) | 53 | Some(&text[pos..]) |
54 | } | 54 | } |
55 | 55 | ||
56 | pub fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { | 56 | pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option<LocalEdit> { |
57 | let let_stmt: &ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; | 57 | assert_eq!(file.syntax().text().char_at(eq_offset), Some('=')); |
58 | let let_stmt: &ast::LetStmt = find_node_at_offset(file.syntax(), eq_offset)?; | ||
58 | if let_stmt.has_semi() { | 59 | if let_stmt.has_semi() { |
59 | return None; | 60 | return None; |
60 | } | 61 | } |
61 | if let Some(expr) = let_stmt.initializer() { | 62 | if let Some(expr) = let_stmt.initializer() { |
62 | let expr_range = expr.syntax().range(); | 63 | let expr_range = expr.syntax().range(); |
63 | if expr_range.contains(offset) && offset != expr_range.start() { | 64 | if expr_range.contains(eq_offset) && eq_offset != expr_range.start() { |
64 | return None; | 65 | return None; |
65 | } | 66 | } |
66 | if file | 67 | if file |
67 | .syntax() | 68 | .syntax() |
68 | .text() | 69 | .text() |
69 | .slice(offset..expr_range.start()) | 70 | .slice(eq_offset..expr_range.start()) |
70 | .contains('\n') | 71 | .contains('\n') |
71 | { | 72 | { |
72 | return None; | 73 | return None; |
@@ -84,54 +85,44 @@ pub fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { | |||
84 | }) | 85 | }) |
85 | } | 86 | } |
86 | 87 | ||
87 | pub fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { | 88 | pub fn on_dot_typed(file: &SourceFile, dot_offset: TextUnit) -> Option<LocalEdit> { |
88 | let before_dot_offset = offset - TextUnit::of_char('.'); | 89 | assert_eq!(file.syntax().text().char_at(dot_offset), Some('.')); |
89 | 90 | ||
90 | let whitespace = find_leaf_at_offset(file.syntax(), before_dot_offset).left_biased()?; | 91 | let whitespace = find_leaf_at_offset(file.syntax(), dot_offset) |
91 | 92 | .left_biased() | |
92 | // find whitespace just left of the dot | 93 | .and_then(ast::Whitespace::cast)?; |
93 | ast::Whitespace::cast(whitespace)?; | ||
94 | |||
95 | // make sure there is a method call | ||
96 | let method_call = whitespace | ||
97 | .siblings(Direction::Prev) | ||
98 | // first is whitespace | ||
99 | .skip(1) | ||
100 | .next()?; | ||
101 | |||
102 | ast::MethodCallExpr::cast(method_call)?; | ||
103 | |||
104 | // find how much the _method call is indented | ||
105 | let method_chain_indent = method_call | ||
106 | .parent()? | ||
107 | .siblings(Direction::Prev) | ||
108 | .skip(1) | ||
109 | .next()? | ||
110 | .leaf_text() | ||
111 | .map(|x| last_line_indent_in_whitespace(x))?; | ||
112 | |||
113 | let current_indent = TextUnit::of_str(last_line_indent_in_whitespace(whitespace.leaf_text()?)); | ||
114 | // TODO: indent is always 4 spaces now. A better heuristic could look on the previous line(s) | ||
115 | |||
116 | let target_indent = TextUnit::of_str(method_chain_indent) + TextUnit::from_usize(4); | ||
117 | |||
118 | let diff = target_indent - current_indent; | ||
119 | |||
120 | let indent = "".repeat(diff.to_usize()); | ||
121 | 94 | ||
122 | let cursor_position = offset + diff; | 95 | let current_indent = { |
96 | let text = whitespace.text(); | ||
97 | let newline = text.rfind('\n')?; | ||
98 | &text[newline + 1..] | ||
99 | }; | ||
100 | let current_indent_len = TextUnit::of_str(current_indent); | ||
101 | |||
102 | // Make sure dot is a part of call chain | ||
103 | let field_expr = whitespace | ||
104 | .syntax() | ||
105 | .parent() | ||
106 | .and_then(ast::FieldExpr::cast)?; | ||
107 | let prev_indent = leading_indent(field_expr.syntax())?; | ||
108 | let target_indent = format!(" {}", prev_indent); | ||
109 | let target_indent_len = TextUnit::of_str(&target_indent); | ||
110 | if current_indent_len == target_indent_len { | ||
111 | return None; | ||
112 | } | ||
123 | let mut edit = TextEditBuilder::default(); | 113 | let mut edit = TextEditBuilder::default(); |
124 | edit.insert(before_dot_offset, indent); | 114 | edit.replace( |
125 | Some(LocalEdit { | 115 | TextRange::from_to(dot_offset - current_indent_len, dot_offset), |
126 | label: "indent dot".to_string(), | 116 | target_indent.into(), |
117 | ); | ||
118 | let res = LocalEdit { | ||
119 | label: "reindent dot".to_string(), | ||
127 | edit: edit.finish(), | 120 | edit: edit.finish(), |
128 | cursor_position: Some(cursor_position), | 121 | cursor_position: Some( |
129 | }) | 122 | dot_offset + target_indent_len - current_indent_len + TextUnit::of_char('.'), |
130 | } | 123 | ), |
131 | 124 | }; | |
132 | /// Finds the last line in the whitespace | 125 | Some(res) |
133 | fn last_line_indent_in_whitespace(ws: &str) -> &str { | ||
134 | ws.split('\n').last().unwrap_or("") | ||
135 | } | 126 | } |
136 | 127 | ||
137 | #[cfg(test)] | 128 | #[cfg(test)] |
@@ -142,12 +133,18 @@ mod tests { | |||
142 | 133 | ||
143 | #[test] | 134 | #[test] |
144 | fn test_on_eq_typed() { | 135 | fn test_on_eq_typed() { |
145 | fn do_check(before: &str, after: &str) { | 136 | fn type_eq(before: &str, after: &str) { |
146 | let (offset, before) = extract_offset(before); | 137 | let (offset, before) = extract_offset(before); |
138 | let mut edit = TextEditBuilder::default(); | ||
139 | edit.insert(offset, "=".to_string()); | ||
140 | let before = edit.finish().apply(&before); | ||
147 | let file = SourceFile::parse(&before); | 141 | let file = SourceFile::parse(&before); |
148 | let result = on_eq_typed(&file, offset).unwrap(); | 142 | if let Some(result) = on_eq_typed(&file, offset) { |
149 | let actual = result.edit.apply(&before); | 143 | let actual = result.edit.apply(&before); |
150 | assert_eq_text!(after, &actual); | 144 | assert_eq_text!(after, &actual); |
145 | } else { | ||
146 | assert_eq_text!(&before, after) | ||
147 | }; | ||
151 | } | 148 | } |
152 | 149 | ||
153 | // do_check(r" | 150 | // do_check(r" |
@@ -159,10 +156,10 @@ mod tests { | |||
159 | // let foo =; | 156 | // let foo =; |
160 | // } | 157 | // } |
161 | // "); | 158 | // "); |
162 | do_check( | 159 | type_eq( |
163 | r" | 160 | r" |
164 | fn foo() { | 161 | fn foo() { |
165 | let foo =<|> 1 + 1 | 162 | let foo <|> 1 + 1 |
166 | } | 163 | } |
167 | ", | 164 | ", |
168 | r" | 165 | r" |
@@ -184,112 +181,113 @@ fn foo() { | |||
184 | // "); | 181 | // "); |
185 | } | 182 | } |
186 | 183 | ||
184 | fn type_dot(before: &str, after: &str) { | ||
185 | let (offset, before) = extract_offset(before); | ||
186 | let mut edit = TextEditBuilder::default(); | ||
187 | edit.insert(offset, ".".to_string()); | ||
188 | let before = edit.finish().apply(&before); | ||
189 | let file = SourceFile::parse(&before); | ||
190 | if let Some(result) = on_dot_typed(&file, offset) { | ||
191 | let actual = result.edit.apply(&before); | ||
192 | assert_eq_text!(after, &actual); | ||
193 | } else { | ||
194 | assert_eq_text!(&before, after) | ||
195 | }; | ||
196 | } | ||
197 | |||
187 | #[test] | 198 | #[test] |
188 | fn test_on_dot_typed() { | 199 | fn indents_new_chain_call() { |
189 | fn do_check(before: &str, after: &str) { | 200 | type_dot( |
190 | let (offset, before) = extract_offset(before); | ||
191 | let file = SourceFile::parse(&before); | ||
192 | if let Some(result) = on_eq_typed(&file, offset) { | ||
193 | let actual = result.edit.apply(&before); | ||
194 | assert_eq_text!(after, &actual); | ||
195 | }; | ||
196 | } | ||
197 | // indent if continuing chain call | ||
198 | do_check( | ||
199 | r" | 201 | r" |
200 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 202 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
201 | self.child_impl(db, name) | 203 | self.child_impl(db, name) |
202 | .<|> | 204 | <|> |
203 | } | 205 | } |
204 | ", | 206 | ", |
205 | r" | 207 | r" |
206 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 208 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
207 | self.child_impl(db, name) | 209 | self.child_impl(db, name) |
208 | . | 210 | . |
209 | } | 211 | } |
210 | ", | 212 | ", |
211 | ); | 213 | ); |
212 | 214 | type_dot( | |
213 | // do not indent if already indented | ||
214 | do_check( | ||
215 | r" | 215 | r" |
216 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 216 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
217 | self.child_impl(db, name) | 217 | self.child_impl(db, name) |
218 | .<|> | 218 | <|> |
219 | } | 219 | } |
220 | ", | 220 | ", |
221 | r" | 221 | r" |
222 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 222 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
223 | self.child_impl(db, name) | 223 | self.child_impl(db, name) |
224 | . | 224 | . |
225 | } | ||
226 | ", | ||
227 | ) | ||
225 | } | 228 | } |
226 | ", | ||
227 | ); | ||
228 | 229 | ||
229 | // indent if the previous line is already indented | 230 | #[test] |
230 | do_check( | 231 | fn indents_continued_chain_call() { |
232 | type_dot( | ||
231 | r" | 233 | r" |
232 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 234 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
233 | self.child_impl(db, name) | 235 | self.child_impl(db, name) |
234 | .first() | 236 | .first() |
235 | .<|> | 237 | <|> |
236 | } | 238 | } |
237 | ", | 239 | ", |
238 | r" | 240 | r" |
239 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 241 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
240 | self.child_impl(db, name) | 242 | self.child_impl(db, name) |
241 | .first() | 243 | .first() |
242 | . | 244 | . |
243 | } | 245 | } |
244 | ", | 246 | ", |
245 | ); | 247 | ); |
246 | 248 | type_dot( | |
247 | // don't indent if indent matches previous line | ||
248 | do_check( | ||
249 | r" | 249 | r" |
250 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 250 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
251 | self.child_impl(db, name) | 251 | self.child_impl(db, name) |
252 | .first() | 252 | .first() |
253 | .<|> | 253 | <|> |
254 | } | 254 | } |
255 | ", | 255 | ", |
256 | r" | 256 | r" |
257 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 257 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
258 | self.child_impl(db, name) | 258 | self.child_impl(db, name) |
259 | .first() | 259 | .first() |
260 | . | 260 | . |
261 | } | 261 | } |
262 | ", | 262 | ", |
263 | ); | 263 | ); |
264 | } | ||
264 | 265 | ||
265 | // don't indent if there is no method call on previous line | 266 | #[test] |
266 | do_check( | 267 | fn dont_indent_freestanding_dot() { |
268 | type_dot( | ||
267 | r" | 269 | r" |
268 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 270 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
269 | .<|> | 271 | <|> |
270 | } | 272 | } |
271 | ", | 273 | ", |
272 | r" | 274 | r" |
273 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 275 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
274 | . | 276 | . |
275 | } | 277 | } |
276 | ", | 278 | ", |
277 | ); | 279 | ); |
278 | 280 | type_dot( | |
279 | // indent to match previous expr | ||
280 | do_check( | ||
281 | r" | 281 | r" |
282 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 282 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
283 | self.child_impl(db, name) | 283 | <|> |
284 | .<|> | 284 | } |
285 | } | 285 | ", |
286 | ", | ||
287 | r" | 286 | r" |
288 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | 287 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { |
289 | self.child_impl(db, name) | ||
290 | . | 288 | . |
291 | } | 289 | } |
292 | ", | 290 | ", |
293 | ); | 291 | ); |
294 | } | 292 | } |
295 | 293 | ||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 0dda9548a..5f4b27149 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -9,7 +9,7 @@ use languageserver_types::{ | |||
9 | SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, | 9 | SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, |
10 | }; | 10 | }; |
11 | use ra_ide_api::{ | 11 | use ra_ide_api::{ |
12 | FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, SourceChange, | 12 | FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, |
13 | }; | 13 | }; |
14 | use ra_syntax::{TextUnit, AstNode}; | 14 | use ra_syntax::{TextUnit, AstNode}; |
15 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
@@ -92,35 +92,30 @@ pub fn handle_on_type_formatting( | |||
92 | world: ServerWorld, | 92 | world: ServerWorld, |
93 | params: req::DocumentOnTypeFormattingParams, | 93 | params: req::DocumentOnTypeFormattingParams, |
94 | ) -> Result<Option<Vec<TextEdit>>> { | 94 | ) -> Result<Option<Vec<TextEdit>>> { |
95 | let analysis: Option<Box<Fn(FilePosition) -> Option<SourceChange>>> = match params.ch.as_str() { | 95 | let file_id = params.text_document.try_conv_with(&world)?; |
96 | "=" => Some(Box::new(|pos| world.analysis().on_eq_typed(pos))), | 96 | let line_index = world.analysis().file_line_index(file_id); |
97 | "." => Some(Box::new(|pos| world.analysis().on_dot_typed(pos))), | 97 | let position = FilePosition { |
98 | _ => None, | 98 | file_id, |
99 | /// in `ra_ide_api`, the `on_type` invariant is that | ||
100 | /// `text.char_at(position) == typed_char`. | ||
101 | offset: params.position.conv_with(&line_index) - TextUnit::of_char('.'), | ||
99 | }; | 102 | }; |
100 | 103 | ||
101 | if let Some(ana) = analysis { | 104 | let edit = match params.ch.as_str() { |
102 | let file_id = params.text_document.try_conv_with(&world)?; | 105 | "=" => world.analysis().on_eq_typed(position), |
103 | let line_index = world.analysis().file_line_index(file_id); | 106 | "." => world.analysis().on_dot_typed(position), |
104 | let position = FilePosition { | 107 | _ => return Ok(None), |
105 | file_id, | 108 | }; |
106 | offset: params.position.conv_with(&line_index), | 109 | let mut edit = match edit { |
107 | }; | 110 | Some(it) => it, |
111 | None => return Ok(None), | ||
112 | }; | ||
108 | 113 | ||
109 | if let Some(mut action) = ana(position) { | 114 | // This should be a single-file edit |
110 | let change: Vec<TextEdit> = action | 115 | let edit = edit.source_file_edits.pop().unwrap(); |
111 | .source_file_edits | ||
112 | .pop() | ||
113 | .unwrap() | ||
114 | .edit | ||
115 | .as_atoms() | ||
116 | .iter() | ||
117 | .map_conv_with(&line_index) | ||
118 | .collect(); | ||
119 | return Ok(Some(change)); | ||
120 | } | ||
121 | } | ||
122 | 116 | ||
123 | return Ok(None); | 117 | let change: Vec<TextEdit> = edit.edit.conv_with(&line_index); |
118 | return Ok(Some(change)); | ||
124 | } | 119 | } |
125 | 120 | ||
126 | pub fn handle_document_symbol( | 121 | pub fn handle_document_symbol( |