diff options
author | Aleksey Kladov <[email protected]> | 2018-08-23 18:55:23 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-23 18:55:23 +0100 |
commit | 6dcf87fb5f17393028a031b00a562ea8b74267ca (patch) | |
tree | 05de66dc2944ca78e34b507f80e7e12056d4f867 /crates/libeditor/src | |
parent | ec706175645172ee4bd5d3d4c0645ffb45d79bbf (diff) |
Start join-lines
Diffstat (limited to 'crates/libeditor/src')
-rw-r--r-- | crates/libeditor/src/code_actions.rs | 1 | ||||
-rw-r--r-- | crates/libeditor/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/libeditor/src/typing.rs | 81 |
3 files changed, 85 insertions, 1 deletions
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index 6c41923dd..c25ee973c 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs | |||
@@ -14,6 +14,7 @@ use libsyntax2::{ | |||
14 | 14 | ||
15 | use {TextUnit, EditBuilder, Edit}; | 15 | use {TextUnit, EditBuilder, Edit}; |
16 | 16 | ||
17 | #[derive(Debug)] | ||
17 | pub struct ActionResult { | 18 | pub struct ActionResult { |
18 | pub edit: Edit, | 19 | pub edit: Edit, |
19 | pub cursor_position: Option<TextUnit>, | 20 | pub cursor_position: Option<TextUnit>, |
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs index 6bae7a3fa..f8bc73ae9 100644 --- a/crates/libeditor/src/lib.rs +++ b/crates/libeditor/src/lib.rs | |||
@@ -7,11 +7,12 @@ mod symbols; | |||
7 | mod line_index; | 7 | mod line_index; |
8 | mod edit; | 8 | mod edit; |
9 | mod code_actions; | 9 | mod code_actions; |
10 | mod typing; | ||
10 | 11 | ||
11 | use libsyntax2::{ | 12 | use libsyntax2::{ |
12 | ast::{self, NameOwner}, | 13 | ast::{self, NameOwner}, |
13 | AstNode, | 14 | AstNode, |
14 | algo::{walk, find_leaf_at_offset}, | 15 | algo::{walk, find_leaf_at_offset, find_covering_node}, |
15 | SyntaxKind::{self, *}, | 16 | SyntaxKind::{self, *}, |
16 | }; | 17 | }; |
17 | pub use libsyntax2::{ParsedFile, TextRange, TextUnit}; | 18 | pub use libsyntax2::{ParsedFile, TextRange, TextUnit}; |
@@ -24,6 +25,7 @@ pub use self::{ | |||
24 | ActionResult, find_node, | 25 | ActionResult, find_node, |
25 | flip_comma, add_derive, add_impl, | 26 | flip_comma, add_derive, add_impl, |
26 | }, | 27 | }, |
28 | typing::join_lines, | ||
27 | }; | 29 | }; |
28 | 30 | ||
29 | #[derive(Debug)] | 31 | #[derive(Debug)] |
diff --git a/crates/libeditor/src/typing.rs b/crates/libeditor/src/typing.rs new file mode 100644 index 000000000..f49dd0fdc --- /dev/null +++ b/crates/libeditor/src/typing.rs | |||
@@ -0,0 +1,81 @@ | |||
1 | use libsyntax2::{ | ||
2 | TextUnit, TextRange, SyntaxNodeRef, | ||
3 | ast, | ||
4 | algo::{ | ||
5 | walk::preorder, | ||
6 | find_covering_node, | ||
7 | }, | ||
8 | }; | ||
9 | |||
10 | use {ActionResult, EditBuilder}; | ||
11 | |||
12 | pub fn join_lines(file: &ast::ParsedFile, range: TextRange) -> ActionResult { | ||
13 | let range = if range.is_empty() { | ||
14 | let text = file.syntax().text(); | ||
15 | let text = &text[TextRange::from_to(range.start(), TextUnit::of_str(&text))]; | ||
16 | let pos = text.bytes().take_while(|&b| b != b'\n').count(); | ||
17 | if pos == text.len() { | ||
18 | return ActionResult { | ||
19 | edit: EditBuilder::new().finish(), | ||
20 | cursor_position: None | ||
21 | }; | ||
22 | } | ||
23 | let pos: TextUnit = (pos as u32).into(); | ||
24 | TextRange::offset_len( | ||
25 | range.start() + pos, | ||
26 | TextUnit::of_char('\n'), | ||
27 | ) | ||
28 | } else { | ||
29 | range | ||
30 | }; | ||
31 | let node = find_covering_node(file.syntax(), range); | ||
32 | let mut edit = EditBuilder::new(); | ||
33 | for node in preorder(node) { | ||
34 | let text = match node.leaf_text() { | ||
35 | Some(text) => text, | ||
36 | None => continue, | ||
37 | }; | ||
38 | let range = match intersect(range, node.range()) { | ||
39 | Some(range) => range, | ||
40 | None => continue, | ||
41 | } - node.range().start(); | ||
42 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { | ||
43 | let pos: TextUnit = (pos as u32).into(); | ||
44 | let off = node.range().start() + range.start() + pos; | ||
45 | remove_newline(&mut edit, node, text.as_str(), off); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | ActionResult { | ||
50 | edit: edit.finish(), | ||
51 | cursor_position: None, | ||
52 | } | ||
53 | } | ||
54 | |||
55 | fn intersect(r1: TextRange, r2: TextRange) -> Option<TextRange> { | ||
56 | let start = r1.start().max(r2.start()); | ||
57 | let end = r1.end().min(r2.end()); | ||
58 | if start <= end { | ||
59 | Some(TextRange::from_to(start, end)) | ||
60 | } else { | ||
61 | None | ||
62 | } | ||
63 | } | ||
64 | |||
65 | fn remove_newline( | ||
66 | edit: &mut EditBuilder, | ||
67 | node: SyntaxNodeRef, | ||
68 | node_text: &str, | ||
69 | offset: TextUnit, | ||
70 | ) { | ||
71 | let suff = &node_text[TextRange::from_to( | ||
72 | offset - node.range().start() + TextUnit::of_char('\n'), | ||
73 | TextUnit::of_str(node_text), | ||
74 | )]; | ||
75 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); | ||
76 | |||
77 | edit.replace( | ||
78 | TextRange::offset_len(offset, ((spaces + 1) as u32).into()), | ||
79 | " ".to_string(), | ||
80 | ); | ||
81 | } | ||