aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor')
-rw-r--r--crates/ra_editor/src/lib.rs2
-rw-r--r--crates/ra_editor/src/typing.rs101
2 files changed, 100 insertions, 3 deletions
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 2a801f7da..fe0045378 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -35,7 +35,7 @@ pub use self::{
35 flip_comma, add_derive, add_impl, 35 flip_comma, add_derive, add_impl,
36 introduce_variable, 36 introduce_variable,
37 }, 37 },
38 typing::{join_lines, on_eq_typed}, 38 typing::{join_lines, on_eq_typed, on_enter},
39 completion::{scope_completion, CompletionItem}, 39 completion::{scope_completion, CompletionItem},
40 folding_ranges::{Fold, FoldKind, folding_ranges} 40 folding_ranges::{Fold, FoldKind, folding_ranges}
41}; 41};
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 512076941..3384389d1 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind, 4 TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind,
5 ast, 5 ast,
6 algo::{ 6 algo::{
7 find_covering_node, 7 find_covering_node, find_leaf_at_offset, LeafAtOffset,
8 }, 8 },
9 text_utils::{intersect, contains_offset_nonstrict}, 9 text_utils::{intersect, contains_offset_nonstrict},
10 SyntaxKind::*, 10 SyntaxKind::*,
@@ -56,6 +56,58 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
56 } 56 }
57} 57}
58 58
59pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
60 let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().filter(|it| it.kind() == COMMENT)?;
61 let prefix = comment_preffix(comment)?;
62 if offset < comment.range().start() + TextUnit::of_str(prefix) {
63 return None;
64 }
65
66 let indent = node_indent(file, comment)?;
67 let inserted = format!("\n{}{}", indent, prefix);
68 let cursor_position = offset + TextUnit::of_str(&inserted);
69 let mut edit = EditBuilder::new();
70 edit.insert(offset, inserted);
71 Some(LocalEdit {
72 edit: edit.finish(),
73 cursor_position: Some(cursor_position),
74 })
75}
76
77fn comment_preffix(comment: SyntaxNodeRef) -> Option<&'static str> {
78 let text = comment.leaf_text().unwrap();
79 let res = if text.starts_with("///") {
80 "/// "
81 } else if text.starts_with("//!") {
82 "//! "
83 } else if text.starts_with("//") {
84 "// "
85 } else {
86 return None;
87 };
88 Some(res)
89}
90
91fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
92 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
93 LeafAtOffset::Between(l, r) => {
94 assert!(r == node);
95 l
96 }
97 LeafAtOffset::Single(n) => {
98 assert!(n == node);
99 return Some("")
100 }
101 LeafAtOffset::None => unreachable!(),
102 };
103 if ws.kind() != WHITESPACE {
104 return None;
105 }
106 let text = ws.leaf_text().unwrap();
107 let pos = text.as_str().rfind('\n').map(|it| it + 1).unwrap_or(0);
108 Some(&text[pos..])
109}
110
59pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> { 111pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> {
60 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 112 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
61 if let_stmt.has_semi() { 113 if let_stmt.has_semi() {
@@ -187,7 +239,7 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
187#[cfg(test)] 239#[cfg(test)]
188mod tests { 240mod tests {
189 use super::*; 241 use super::*;
190 use test_utils::{check_action, extract_range, extract_offset}; 242 use test_utils::{check_action, extract_range, extract_offset, add_cursor};
191 243
192 fn check_join_lines(before: &str, after: &str) { 244 fn check_join_lines(before: &str, after: &str) {
193 check_action(before, after, |file, offset| { 245 check_action(before, after, |file, offset| {
@@ -344,4 +396,49 @@ fn foo() {
344 // } 396 // }
345 // "); 397 // ");
346 } 398 }
399
400 #[test]
401 fn test_on_enter() {
402 fn apply_on_enter(before: &str) -> Option<String> {
403 let (offset, before) = extract_offset(before);
404 let file = File::parse(&before);
405 let result = on_enter(&file, offset)?;
406 let actual = result.edit.apply(&before);
407 let actual = add_cursor(&actual, result.cursor_position.unwrap());
408 Some(actual)
409 }
410
411 fn do_check(before: &str, after: &str) {
412 let actual = apply_on_enter(before).unwrap();
413 assert_eq_text!(after, &actual);
414 }
415
416 fn do_check_noop(text: &str) {
417 assert!(apply_on_enter(text).is_none())
418 }
419
420 do_check(r"
421/// Some docs<|>
422fn foo() {
423}
424", r"
425/// Some docs
426/// <|>
427fn foo() {
428}
429");
430 do_check(r"
431impl S {
432 /// Some<|> docs.
433 fn foo() {}
434}
435", r"
436impl S {
437 /// Some
438 /// <|> docs.
439 fn foo() {}
440}
441");
442 do_check_noop(r"<|>//! docz");
443 }
347} 444}