From 6dcf87fb5f17393028a031b00a562ea8b74267ca Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 23 Aug 2018 20:55:23 +0300 Subject: Start join-lines --- crates/libeditor/src/typing.rs | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 crates/libeditor/src/typing.rs (limited to 'crates/libeditor/src/typing.rs') 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 @@ +use libsyntax2::{ + TextUnit, TextRange, SyntaxNodeRef, + ast, + algo::{ + walk::preorder, + find_covering_node, + }, +}; + +use {ActionResult, EditBuilder}; + +pub fn join_lines(file: &ast::ParsedFile, range: TextRange) -> ActionResult { + let range = if range.is_empty() { + let text = file.syntax().text(); + let text = &text[TextRange::from_to(range.start(), TextUnit::of_str(&text))]; + let pos = text.bytes().take_while(|&b| b != b'\n').count(); + if pos == text.len() { + return ActionResult { + edit: EditBuilder::new().finish(), + cursor_position: None + }; + } + let pos: TextUnit = (pos as u32).into(); + TextRange::offset_len( + range.start() + pos, + TextUnit::of_char('\n'), + ) + } else { + range + }; + let node = find_covering_node(file.syntax(), range); + let mut edit = EditBuilder::new(); + for node in preorder(node) { + let text = match node.leaf_text() { + Some(text) => text, + None => continue, + }; + let range = match intersect(range, node.range()) { + Some(range) => range, + None => continue, + } - node.range().start(); + for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { + let pos: TextUnit = (pos as u32).into(); + let off = node.range().start() + range.start() + pos; + remove_newline(&mut edit, node, text.as_str(), off); + } + } + + ActionResult { + edit: edit.finish(), + cursor_position: None, + } +} + +fn intersect(r1: TextRange, r2: TextRange) -> Option { + let start = r1.start().max(r2.start()); + let end = r1.end().min(r2.end()); + if start <= end { + Some(TextRange::from_to(start, end)) + } else { + None + } +} + +fn remove_newline( + edit: &mut EditBuilder, + node: SyntaxNodeRef, + node_text: &str, + offset: TextUnit, +) { + let suff = &node_text[TextRange::from_to( + offset - node.range().start() + TextUnit::of_char('\n'), + TextUnit::of_str(node_text), + )]; + let spaces = suff.bytes().take_while(|&b| b == b' ').count(); + + edit.replace( + TextRange::offset_len(offset, ((spaces + 1) as u32).into()), + " ".to_string(), + ); +} -- cgit v1.2.3