diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 30 | ||||
-rw-r--r-- | crates/ra_editor/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_editor/src/typing.rs | 169 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 14 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 65 |
6 files changed, 225 insertions, 57 deletions
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 77f77e9a8..c8f846c56 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -12,41 +12,39 @@ macro_rules! ctry { | |||
12 | }; | 12 | }; |
13 | } | 13 | } |
14 | 14 | ||
15 | mod db; | ||
16 | mod imp; | ||
17 | mod completion; | 15 | mod completion; |
16 | mod db; | ||
18 | mod goto_defenition; | 17 | mod goto_defenition; |
19 | mod symbol_index; | 18 | mod imp; |
20 | pub mod mock_analysis; | 19 | pub mod mock_analysis; |
21 | mod runnables; | 20 | mod runnables; |
21 | mod symbol_index; | ||
22 | 22 | ||
23 | mod extend_selection; | 23 | mod extend_selection; |
24 | mod syntax_highlighting; | ||
25 | mod hover; | 24 | mod hover; |
25 | mod syntax_highlighting; | ||
26 | 26 | ||
27 | use std::{fmt, sync::Arc}; | 27 | use std::{fmt, sync::Arc}; |
28 | 28 | ||
29 | use rustc_hash::FxHashMap; | 29 | use ra_syntax::{SmolStr, SourceFileNode, SyntaxKind, TextRange, TextUnit}; |
30 | use ra_syntax::{SourceFileNode, TextRange, TextUnit, SmolStr, SyntaxKind}; | ||
31 | use ra_text_edit::TextEdit; | 30 | use ra_text_edit::TextEdit; |
32 | use rayon::prelude::*; | 31 | use rayon::prelude::*; |
33 | use relative_path::RelativePathBuf; | 32 | use relative_path::RelativePathBuf; |
33 | use rustc_hash::FxHashMap; | ||
34 | use salsa::ParallelDatabase; | 34 | use salsa::ParallelDatabase; |
35 | 35 | ||
36 | use crate::symbol_index::{SymbolIndex, FileSymbol}; | 36 | use crate::symbol_index::{FileSymbol, SymbolIndex}; |
37 | 37 | ||
38 | pub use crate::{ | 38 | pub use crate::{ |
39 | completion::{CompletionItem, CompletionItemKind, InsertText}, | 39 | completion::{CompletionItem, CompletionItemKind, InsertText}, |
40 | runnables::{Runnable, RunnableKind}, | 40 | runnables::{Runnable, RunnableKind}, |
41 | }; | 41 | }; |
42 | pub use ra_editor::{ | ||
43 | Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity | ||
44 | }; | ||
45 | pub use hir::FnSignatureInfo; | 42 | pub use hir::FnSignatureInfo; |
43 | pub use ra_editor::{Fold, FoldKind, HighlightedRange, LineIndex, Severity, StructureNode}; | ||
46 | 44 | ||
47 | pub use ra_db::{ | 45 | pub use ra_db::{ |
48 | Canceled, Cancelable, FilePosition, FileRange, LocalSyntaxPtr, | 46 | Cancelable, Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, FilesDatabase, |
49 | CrateGraph, CrateId, SourceRootId, FileId, SyntaxDatabase, FilesDatabase | 47 | LocalSyntaxPtr, SourceRootId, SyntaxDatabase, |
50 | }; | 48 | }; |
51 | 49 | ||
52 | #[derive(Default)] | 50 | #[derive(Default)] |
@@ -346,7 +344,7 @@ impl Analysis { | |||
346 | let edit = ra_editor::on_enter(&file, position.offset)?; | 344 | let edit = ra_editor::on_enter(&file, position.offset)?; |
347 | Some(SourceChange::from_local_edit(position.file_id, edit)) | 345 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
348 | } | 346 | } |
349 | /// Returns an edit which should be applied after `=` was typed. Primaraly, | 347 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
350 | /// this works when adding `let =`. | 348 | /// this works when adding `let =`. |
351 | // FIXME: use a snippet completion instead of this hack here. | 349 | // FIXME: use a snippet completion instead of this hack here. |
352 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { | 350 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { |
@@ -354,6 +352,12 @@ impl Analysis { | |||
354 | let edit = ra_editor::on_eq_typed(&file, position.offset)?; | 352 | let edit = ra_editor::on_eq_typed(&file, position.offset)?; |
355 | Some(SourceChange::from_local_edit(position.file_id, edit)) | 353 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
356 | } | 354 | } |
355 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. | ||
356 | pub fn on_dot_typed(&self, position: FilePosition) -> Option<SourceChange> { | ||
357 | let file = self.db.source_file(position.file_id); | ||
358 | let edit = ra_editor::on_dot_typed(&file, position.offset)?; | ||
359 | Some(SourceChange::from_local_edit(position.file_id, edit)) | ||
360 | } | ||
357 | /// Returns a tree representation of symbols in the file. Useful to draw a | 361 | /// Returns a tree representation of symbols in the file. Useful to draw a |
358 | /// file outline. | 362 | /// file outline. |
359 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { | 363 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { |
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index ac283e2e0..a3c85ed5d 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -16,7 +16,7 @@ pub use self::{ | |||
16 | line_index::{LineCol, LineIndex}, | 16 | line_index::{LineCol, LineIndex}, |
17 | line_index_utils::translate_offset_with_edit, | 17 | line_index_utils::translate_offset_with_edit, |
18 | structure::{file_structure, StructureNode}, | 18 | structure::{file_structure, StructureNode}, |
19 | typing::{join_lines, on_enter, on_eq_typed}, | 19 | typing::{join_lines, on_enter, on_dot_typed, on_eq_typed}, |
20 | diagnostics::diagnostics | 20 | diagnostics::diagnostics |
21 | }; | 21 | }; |
22 | use ra_text_edit::TextEditBuilder; | 22 | use ra_text_edit::TextEditBuilder; |
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index 1b568e96c..12500854c 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs | |||
@@ -1,17 +1,17 @@ | |||
1 | use std::mem; | 1 | use std::mem; |
2 | 2 | ||
3 | use itertools::Itertools; | ||
3 | use ra_syntax::{ | 4 | use ra_syntax::{ |
4 | algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, | 5 | algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, |
5 | ast, | 6 | ast, |
6 | text_utils::intersect, | 7 | text_utils::intersect, |
7 | AstNode, SourceFileNode, SyntaxKind, | 8 | AstNode, Direction, SourceFileNode, SyntaxKind, |
8 | SyntaxKind::*, | 9 | SyntaxKind::*, |
9 | SyntaxNodeRef, TextRange, TextUnit, | 10 | SyntaxNodeRef, TextRange, TextUnit, |
10 | }; | 11 | }; |
11 | use ra_text_edit::text_utils::contains_offset_nonstrict; | 12 | use ra_text_edit::text_utils::contains_offset_nonstrict; |
12 | use itertools::Itertools; | ||
13 | 13 | ||
14 | use crate::{find_node_at_offset, TextEditBuilder, LocalEdit}; | 14 | use crate::{find_node_at_offset, LocalEdit, TextEditBuilder}; |
15 | 15 | ||
16 | pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit { | 16 | pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit { |
17 | let range = if range.is_empty() { | 17 | let range = if range.is_empty() { |
@@ -136,6 +136,56 @@ pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> | |||
136 | }) | 136 | }) |
137 | } | 137 | } |
138 | 138 | ||
139 | pub fn on_dot_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> { | ||
140 | let before_dot_offset = offset - TextUnit::of_char('.'); | ||
141 | |||
142 | let whitespace = find_leaf_at_offset(file.syntax(), before_dot_offset).left_biased()?; | ||
143 | |||
144 | // find whitespace just left of the dot | ||
145 | ast::Whitespace::cast(whitespace)?; | ||
146 | |||
147 | // make sure there is a method call | ||
148 | let method_call = whitespace | ||
149 | .siblings(Direction::Prev) | ||
150 | // first is whitespace | ||
151 | .skip(1) | ||
152 | .next()?; | ||
153 | |||
154 | ast::MethodCallExprNode::cast(method_call)?; | ||
155 | |||
156 | // find how much the _method call is indented | ||
157 | let method_chain_indent = method_call | ||
158 | .parent()? | ||
159 | .siblings(Direction::Prev) | ||
160 | .skip(1) | ||
161 | .next()? | ||
162 | .leaf_text() | ||
163 | .map(|x| last_line_indent_in_whitespace(x))?; | ||
164 | |||
165 | let current_indent = TextUnit::of_str(last_line_indent_in_whitespace(whitespace.leaf_text()?)); | ||
166 | // TODO: indent is always 4 spaces now. A better heuristic could look on the previous line(s) | ||
167 | |||
168 | let target_indent = TextUnit::of_str(method_chain_indent) + TextUnit::from_usize(4); | ||
169 | |||
170 | let diff = target_indent - current_indent; | ||
171 | |||
172 | let indent = "".repeat(diff.to_usize()); | ||
173 | |||
174 | let cursor_position = offset + diff; | ||
175 | let mut edit = TextEditBuilder::default(); | ||
176 | edit.insert(before_dot_offset, indent); | ||
177 | Some(LocalEdit { | ||
178 | label: "indent dot".to_string(), | ||
179 | edit: edit.finish(), | ||
180 | cursor_position: Some(cursor_position), | ||
181 | }) | ||
182 | } | ||
183 | |||
184 | /// Finds the last line in the whitespace | ||
185 | fn last_line_indent_in_whitespace(ws: &str) -> &str { | ||
186 | ws.split('\n').last().unwrap_or("") | ||
187 | } | ||
188 | |||
139 | fn remove_newline( | 189 | fn remove_newline( |
140 | edit: &mut TextEditBuilder, | 190 | edit: &mut TextEditBuilder, |
141 | node: SyntaxNodeRef, | 191 | node: SyntaxNodeRef, |
@@ -283,7 +333,9 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { | |||
283 | #[cfg(test)] | 333 | #[cfg(test)] |
284 | mod tests { | 334 | mod tests { |
285 | use super::*; | 335 | use super::*; |
286 | use crate::test_utils::{add_cursor, check_action, extract_offset, extract_range, assert_eq_text}; | 336 | use crate::test_utils::{ |
337 | add_cursor, assert_eq_text, check_action, extract_offset, extract_range, | ||
338 | }; | ||
287 | 339 | ||
288 | fn check_join_lines(before: &str, after: &str) { | 340 | fn check_join_lines(before: &str, after: &str) { |
289 | check_action(before, after, |file, offset| { | 341 | check_action(before, after, |file, offset| { |
@@ -615,6 +667,115 @@ fn foo() { | |||
615 | } | 667 | } |
616 | 668 | ||
617 | #[test] | 669 | #[test] |
670 | fn test_on_dot_typed() { | ||
671 | fn do_check(before: &str, after: &str) { | ||
672 | let (offset, before) = extract_offset(before); | ||
673 | let file = SourceFileNode::parse(&before); | ||
674 | if let Some(result) = on_eq_typed(&file, offset) { | ||
675 | let actual = result.edit.apply(&before); | ||
676 | assert_eq_text!(after, &actual); | ||
677 | }; | ||
678 | } | ||
679 | // indent if continuing chain call | ||
680 | do_check( | ||
681 | r" | ||
682 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
683 | self.child_impl(db, name) | ||
684 | .<|> | ||
685 | } | ||
686 | ", | ||
687 | r" | ||
688 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
689 | self.child_impl(db, name) | ||
690 | . | ||
691 | } | ||
692 | ", | ||
693 | ); | ||
694 | |||
695 | // do not indent if already indented | ||
696 | do_check( | ||
697 | r" | ||
698 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
699 | self.child_impl(db, name) | ||
700 | .<|> | ||
701 | } | ||
702 | ", | ||
703 | r" | ||
704 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
705 | self.child_impl(db, name) | ||
706 | . | ||
707 | } | ||
708 | ", | ||
709 | ); | ||
710 | |||
711 | // indent if the previous line is already indented | ||
712 | do_check( | ||
713 | r" | ||
714 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
715 | self.child_impl(db, name) | ||
716 | .first() | ||
717 | .<|> | ||
718 | } | ||
719 | ", | ||
720 | r" | ||
721 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
722 | self.child_impl(db, name) | ||
723 | .first() | ||
724 | . | ||
725 | } | ||
726 | ", | ||
727 | ); | ||
728 | |||
729 | // don't indent if indent matches previous line | ||
730 | do_check( | ||
731 | r" | ||
732 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
733 | self.child_impl(db, name) | ||
734 | .first() | ||
735 | .<|> | ||
736 | } | ||
737 | ", | ||
738 | r" | ||
739 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
740 | self.child_impl(db, name) | ||
741 | .first() | ||
742 | . | ||
743 | } | ||
744 | ", | ||
745 | ); | ||
746 | |||
747 | // don't indent if there is no method call on previous line | ||
748 | do_check( | ||
749 | r" | ||
750 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
751 | .<|> | ||
752 | } | ||
753 | ", | ||
754 | r" | ||
755 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
756 | . | ||
757 | } | ||
758 | ", | ||
759 | ); | ||
760 | |||
761 | // indent to match previous expr | ||
762 | do_check( | ||
763 | r" | ||
764 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
765 | self.child_impl(db, name) | ||
766 | .<|> | ||
767 | } | ||
768 | ", | ||
769 | r" | ||
770 | pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { | ||
771 | self.child_impl(db, name) | ||
772 | . | ||
773 | } | ||
774 | ", | ||
775 | ); | ||
776 | } | ||
777 | |||
778 | #[test] | ||
618 | fn test_on_enter() { | 779 | fn test_on_enter() { |
619 | fn apply_on_enter(before: &str) -> Option<String> { | 780 | fn apply_on_enter(before: &str) -> Option<String> { |
620 | let (offset, before) = extract_offset(before); | 781 | let (offset, before) = extract_offset(before); |
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index a74f9f27b..2599a4ca6 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -37,7 +37,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
37 | document_range_formatting_provider: None, | 37 | document_range_formatting_provider: None, |
38 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { | 38 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { |
39 | first_trigger_character: "=".to_string(), | 39 | first_trigger_character: "=".to_string(), |
40 | more_trigger_character: None, | 40 | more_trigger_character: Some(vec![".".to_string()]), |
41 | }), | 41 | }), |
42 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), | 42 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), |
43 | rename_provider: Some(RenameProviderCapability::Options(RenameOptions { | 43 | rename_provider: Some(RenameProviderCapability::Options(RenameOptions { |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 60d9671de..2dc1be26a 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -1,13 +1,11 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | mod subscriptions; | 2 | mod subscriptions; |
3 | 3 | ||
4 | use std::{ | 4 | use std::{fmt, path::PathBuf, sync::Arc}; |
5 | fmt, | ||
6 | path::PathBuf, | ||
7 | sync::Arc, | ||
8 | }; | ||
9 | 5 | ||
10 | use crossbeam_channel::{unbounded, select, Receiver, Sender, RecvError}; | 6 | use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender}; |
7 | use failure::{bail, format_err}; | ||
8 | use failure_derive::Fail; | ||
11 | use gen_lsp_server::{ | 9 | use gen_lsp_server::{ |
12 | handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, | 10 | handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, |
13 | }; | 11 | }; |
@@ -15,11 +13,9 @@ use languageserver_types::NumberOrString; | |||
15 | use ra_analysis::{Canceled, FileId, LibraryData}; | 13 | use ra_analysis::{Canceled, FileId, LibraryData}; |
16 | use ra_vfs::VfsTask; | 14 | use ra_vfs::VfsTask; |
17 | use rayon; | 15 | use rayon; |
18 | use threadpool::ThreadPool; | ||
19 | use rustc_hash::FxHashSet; | 16 | use rustc_hash::FxHashSet; |
20 | use serde::{de::DeserializeOwned, Serialize}; | 17 | use serde::{de::DeserializeOwned, Serialize}; |
21 | use failure::{format_err, bail}; | 18 | use threadpool::ThreadPool; |
22 | use failure_derive::Fail; | ||
23 | 19 | ||
24 | use crate::{ | 20 | use crate::{ |
25 | main_loop::subscriptions::Subscriptions, | 21 | main_loop::subscriptions::Subscriptions, |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 1baed73ad..51f134e8a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -2,15 +2,16 @@ use std::collections::HashMap; | |||
2 | 2 | ||
3 | use gen_lsp_server::ErrorCode; | 3 | use gen_lsp_server::ErrorCode; |
4 | use languageserver_types::{ | 4 | use languageserver_types::{ |
5 | CodeActionResponse, Command, Diagnostic, | 5 | CodeActionResponse, Command, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, |
6 | DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, | 6 | DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, |
7 | FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position, | 7 | FoldingRangeParams, Hover, HoverContents, Location, MarkedString, MarkupContent, MarkupKind, |
8 | PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, | 8 | ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, |
9 | Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, | 9 | SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, |
10 | HoverContents, DocumentFormattingParams, DocumentHighlight, | ||
11 | }; | 10 | }; |
12 | use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; | 11 | use ra_analysis::{ |
13 | use ra_syntax::{TextUnit, text_utils::intersect}; | 12 | FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, SourceChange, |
13 | }; | ||
14 | use ra_syntax::{text_utils::intersect, TextUnit}; | ||
14 | use ra_text_edit::text_utils::contains_offset_nonstrict; | 15 | use ra_text_edit::text_utils::contains_offset_nonstrict; |
15 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
16 | use serde_json::to_value; | 17 | use serde_json::to_value; |
@@ -92,29 +93,35 @@ pub fn handle_on_type_formatting( | |||
92 | world: ServerWorld, | 93 | world: ServerWorld, |
93 | params: req::DocumentOnTypeFormattingParams, | 94 | params: req::DocumentOnTypeFormattingParams, |
94 | ) -> Result<Option<Vec<TextEdit>>> { | 95 | ) -> Result<Option<Vec<TextEdit>>> { |
95 | if params.ch != "=" { | 96 | let analysis: Option<Box<Fn(FilePosition) -> Option<SourceChange>>> = match params.ch.as_str() { |
96 | return Ok(None); | 97 | "=" => Some(Box::new(|pos| world.analysis().on_eq_typed(pos))), |
98 | "." => Some(Box::new(|pos| world.analysis().on_dot_typed(pos))), | ||
99 | _ => None, | ||
100 | }; | ||
101 | |||
102 | if let Some(ana) = analysis { | ||
103 | let file_id = params.text_document.try_conv_with(&world)?; | ||
104 | let line_index = world.analysis().file_line_index(file_id); | ||
105 | let position = FilePosition { | ||
106 | file_id, | ||
107 | offset: params.position.conv_with(&line_index), | ||
108 | }; | ||
109 | |||
110 | if let Some(mut action) = ana(position) { | ||
111 | let change: Vec<TextEdit> = action | ||
112 | .source_file_edits | ||
113 | .pop() | ||
114 | .unwrap() | ||
115 | .edit | ||
116 | .as_atoms() | ||
117 | .iter() | ||
118 | .map_conv_with(&line_index) | ||
119 | .collect(); | ||
120 | return Ok(Some(change)); | ||
121 | } | ||
97 | } | 122 | } |
98 | 123 | ||
99 | let file_id = params.text_document.try_conv_with(&world)?; | 124 | return Ok(None); |
100 | let line_index = world.analysis().file_line_index(file_id); | ||
101 | let position = FilePosition { | ||
102 | file_id, | ||
103 | offset: params.position.conv_with(&line_index), | ||
104 | }; | ||
105 | let edits = match world.analysis().on_eq_typed(position) { | ||
106 | None => return Ok(None), | ||
107 | Some(mut action) => action | ||
108 | .source_file_edits | ||
109 | .pop() | ||
110 | .unwrap() | ||
111 | .edit | ||
112 | .as_atoms() | ||
113 | .iter() | ||
114 | .map_conv_with(&line_index) | ||
115 | .collect(), | ||
116 | }; | ||
117 | Ok(Some(edits)) | ||
118 | } | 125 | } |
119 | 126 | ||
120 | pub fn handle_document_symbol( | 127 | pub fn handle_document_symbol( |