aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/typing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/typing.rs')
-rw-r--r--crates/libeditor/src/typing.rs81
1 files changed, 81 insertions, 0 deletions
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 @@
1use libsyntax2::{
2 TextUnit, TextRange, SyntaxNodeRef,
3 ast,
4 algo::{
5 walk::preorder,
6 find_covering_node,
7 },
8};
9
10use {ActionResult, EditBuilder};
11
12pub 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
55fn 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
65fn 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}