aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-04-24 22:40:41 +0100
committerAleksey Kladov <[email protected]>2020-04-25 10:59:18 +0100
commitb1d5817dd18b7b5fc102a63b084b1ee7ff4f9996 (patch)
treee5d136c5ba4a6ba96aeeb423e6e3f64ca7cea3f9
parent27a7718880d93f55f905da606d108d3b3c682ab4 (diff)
Convert code to text-size
-rw-r--r--Cargo.lock16
-rw-r--r--crates/ra_assists/src/assist_ctx.rs8
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs8
-rw-r--r--crates/ra_assists/src/handlers/add_derive.rs8
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs8
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs8
-rw-r--r--crates/ra_assists/src/handlers/apply_demorgan.rs2
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs4
-rw-r--r--crates/ra_assists/src/handlers/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs6
-rw-r--r--crates/ra_assists/src/handlers/invert_if.rs2
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs10
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs10
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs4
-rw-r--r--crates/ra_assists/src/handlers/remove_dbg.rs8
-rw-r--r--crates/ra_assists/src/handlers/remove_mut.rs2
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs2
-rw-r--r--crates/ra_assists/src/lib.rs6
-rw-r--r--crates/ra_db/src/lib.rs4
-rw-r--r--crates/ra_hir/src/semantics.rs18
-rw-r--r--crates/ra_hir/src/source_analyzer.rs18
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs4
-rw-r--r--crates/ra_hir_expand/src/lib.rs4
-rw-r--r--crates/ra_hir_ty/src/tests.rs4
-rw-r--r--crates/ra_ide/src/call_info.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs8
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs13
-rw-r--r--crates/ra_ide/src/diagnostics.rs2
-rw-r--r--crates/ra_ide/src/extend_selection.rs42
-rw-r--r--crates/ra_ide/src/folding_ranges.rs4
-rw-r--r--crates/ra_ide/src/hover.rs2
-rw-r--r--crates/ra_ide/src/join_lines.rs38
-rw-r--r--crates/ra_ide/src/lib.rs4
-rw-r--r--crates/ra_ide/src/matching_brace.rs4
-rw-r--r--crates/ra_ide/src/references/rename.rs4
-rw-r--r--crates/ra_ide/src/source_change.rs4
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs12
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs11
-rw-r--r--crates/ra_ide/src/syntax_tree.rs8
-rw-r--r--crates/ra_ide/src/test_utils.rs4
-rw-r--r--crates/ra_ide/src/typing.rs20
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs6
-rw-r--r--crates/ra_ide_db/src/line_index.rs54
-rw-r--r--crates/ra_ide_db/src/line_index_utils.rs48
-rw-r--r--crates/ra_ide_db/src/search.rs9
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs69
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/algo.rs12
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs32
-rw-r--r--crates/ra_syntax/src/fuzz.rs8
-rw-r--r--crates/ra_syntax/src/lib.rs4
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs18
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs4
-rw-r--r--crates/ra_syntax/src/parsing/text_token_source.rs8
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs14
-rw-r--r--crates/ra_syntax/src/ptr.rs2
-rw-r--r--crates/ra_syntax/src/syntax_error.rs6
-rw-r--r--crates/ra_syntax/src/syntax_node.rs4
-rw-r--r--crates/ra_syntax/src/tests.rs8
-rw-r--r--crates/ra_syntax/src/validation.rs4
-rw-r--r--crates/ra_text_edit/Cargo.toml3
-rw-r--r--crates/ra_text_edit/src/lib.rs10
-rw-r--r--crates/ra_text_edit/src/text_edit.rs25
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/conv.rs18
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs18
-rw-r--r--crates/test_utils/Cargo.toml2
-rw-r--r--crates/test_utils/src/lib.rs26
-rw-r--r--docs/dev/syntax.md108
75 files changed, 438 insertions, 456 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d966ebe61..70dfa019d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1180,7 +1180,7 @@ dependencies = [
1180name = "ra_text_edit" 1180name = "ra_text_edit"
1181version = "0.1.0" 1181version = "0.1.0"
1182dependencies = [ 1182dependencies = [
1183 "text_unit", 1183 "text-size",
1184] 1184]
1185 1185
1186[[package]] 1186[[package]]
@@ -1322,13 +1322,11 @@ dependencies = [
1322 1322
1323[[package]] 1323[[package]]
1324name = "rowan" 1324name = "rowan"
1325version = "0.9.1" 1325version = "0.10.0-pre.1"
1326source = "registry+https://github.com/rust-lang/crates.io-index"
1327checksum = "1ea7cadf87a9d8432e85cb4eb86bd2e765ace60c24ef86e79084dcae5d1c5a19"
1328dependencies = [ 1326dependencies = [
1329 "rustc-hash", 1327 "rustc-hash",
1330 "smol_str", 1328 "smol_str",
1331 "text_unit", 1329 "text-size",
1332 "thin-dst", 1330 "thin-dst",
1333] 1331]
1334 1332
@@ -1620,14 +1618,12 @@ version = "0.1.0"
1620dependencies = [ 1618dependencies = [
1621 "difference", 1619 "difference",
1622 "serde_json", 1620 "serde_json",
1623 "text_unit", 1621 "text-size",
1624] 1622]
1625 1623
1626[[package]] 1624[[package]]
1627name = "text_unit" 1625name = "text-size"
1628version = "0.1.10" 1626version = "1.0.0-pre.1"
1629source = "registry+https://github.com/rust-lang/crates.io-index"
1630checksum = "20431e104bfecc1a40872578dbc390e10290a0e9c35fffe3ce6f73c15a9dbfc2"
1631 1627
1632[[package]] 1628[[package]]
1633name = "thin-dst" 1629name = "thin-dst"
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 279163257..2fe7c3de3 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -5,7 +5,7 @@ use ra_fmt::{leading_indent, reindent};
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
7 algo::{self, find_covering_element, find_node_at_offset}, 7 algo::{self, find_covering_element, find_node_at_offset},
8 AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit, 8 AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
9 TokenAtOffset, 9 TokenAtOffset,
10}; 10};
11use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
@@ -178,7 +178,7 @@ impl<'a> AssistGroup<'a> {
178#[derive(Default)] 178#[derive(Default)]
179pub(crate) struct ActionBuilder { 179pub(crate) struct ActionBuilder {
180 edit: TextEditBuilder, 180 edit: TextEditBuilder,
181 cursor_position: Option<TextUnit>, 181 cursor_position: Option<TextSize>,
182 target: Option<TextRange>, 182 target: Option<TextRange>,
183 file: AssistFile, 183 file: AssistFile,
184} 184}
@@ -211,12 +211,12 @@ impl ActionBuilder {
211 } 211 }
212 212
213 /// Append specified `text` at the given `offset` 213 /// Append specified `text` at the given `offset`
214 pub(crate) fn insert(&mut self, offset: TextUnit, text: impl Into<String>) { 214 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
215 self.edit.insert(offset, text.into()) 215 self.edit.insert(offset, text.into())
216 } 216 }
217 217
218 /// Specify desired position of the cursor after the assist is applied. 218 /// Specify desired position of the cursor after the assist is applied.
219 pub(crate) fn set_cursor(&mut self, offset: TextUnit) { 219 pub(crate) fn set_cursor(&mut self, offset: TextSize) {
220 self.cursor_position = Some(offset) 220 self.cursor_position = Some(offset)
221 } 221 }
222 222
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index 15f9b216b..7bb90dba3 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -2,7 +2,7 @@ use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 Direction, SmolStr, 3 Direction, SmolStr,
4 SyntaxKind::{IDENT, WHITESPACE}, 4 SyntaxKind::{IDENT, WHITESPACE},
5 TextRange, TextUnit, 5 TextRange, TextSize,
6}; 6};
7use stdx::SepBy; 7use stdx::SepBy;
8 8
@@ -71,7 +71,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
71 71
72 let cursor_delta = if has_more_derives { 72 let cursor_delta = if has_more_derives {
73 edit.replace(input.syntax().text_range(), new_attr_input); 73 edit.replace(input.syntax().text_range(), new_attr_input);
74 input.syntax().text_range().len() - TextUnit::from_usize(new_attr_input_len) 74 input.syntax().text_range().len() - TextSize::from_usize(new_attr_input_len)
75 } else { 75 } else {
76 let attr_range = attr.syntax().text_range(); 76 let attr_range = attr.syntax().text_range();
77 edit.delete(attr_range); 77 edit.delete(attr_range);
@@ -81,13 +81,13 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
81 .next_sibling_or_token() 81 .next_sibling_or_token()
82 .filter(|t| t.kind() == WHITESPACE) 82 .filter(|t| t.kind() == WHITESPACE)
83 .map(|t| t.text_range()) 83 .map(|t| t.text_range())
84 .unwrap_or_else(|| TextRange::from_to(TextUnit::from(0), TextUnit::from(0))); 84 .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
85 edit.delete(line_break_range); 85 edit.delete(line_break_range);
86 86
87 attr_range.len() + line_break_range.len() 87 attr_range.len() + line_break_range.len()
88 }; 88 };
89 89
90 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - cursor_delta); 90 edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta);
91 buf.push_str("\n}"); 91 buf.push_str("\n}");
92 edit.insert(start_offset, buf); 92 edit.insert(start_offset, buf);
93 }) 93 })
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs
index b0d1a0a80..6254eb7c4 100644
--- a/crates/ra_assists/src/handlers/add_derive.rs
+++ b/crates/ra_assists/src/handlers/add_derive.rs
@@ -1,7 +1,7 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode, AttrsOwner}, 2 ast::{self, AstNode, AttrsOwner},
3 SyntaxKind::{COMMENT, WHITESPACE}, 3 SyntaxKind::{COMMENT, WHITESPACE},
4 TextUnit, 4 TextSize,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
@@ -37,9 +37,9 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> {
37 let offset = match derive_attr { 37 let offset = match derive_attr {
38 None => { 38 None => {
39 edit.insert(node_start, "#[derive()]\n"); 39 edit.insert(node_start, "#[derive()]\n");
40 node_start + TextUnit::of_str("#[derive(") 40 node_start + TextSize::of("#[derive(")
41 } 41 }
42 Some(tt) => tt.syntax().text_range().end() - TextUnit::of_char(')'), 42 Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'),
43 }; 43 };
44 edit.target(nominal.syntax().text_range()); 44 edit.target(nominal.syntax().text_range());
45 edit.set_cursor(offset) 45 edit.set_cursor(offset)
@@ -47,7 +47,7 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> {
47} 47}
48 48
49// Insert `derive` after doc comments. 49// Insert `derive` after doc comments.
50fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { 50fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextSize> {
51 let non_ws_child = nominal 51 let non_ws_child = nominal
52 .syntax() 52 .syntax()
53 .children_with_tokens() 53 .children_with_tokens()
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 6c56d93d8..bc313782b 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -37,8 +37,8 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> {
37 let stmt_range = stmt.syntax().text_range(); 37 let stmt_range = stmt.syntax().text_range();
38 let eq_range = stmt.eq_token()?.text_range(); 38 let eq_range = stmt.eq_token()?.text_range();
39 // Assist should only be applicable if cursor is between 'let' and '=' 39 // Assist should only be applicable if cursor is between 'let' and '='
40 let let_range = TextRange::from_to(stmt_range.start(), eq_range.start()); 40 let let_range = TextRange::new(stmt_range.start(), eq_range.start());
41 let cursor_in_range = ctx.frange.range.is_subrange(&let_range); 41 let cursor_in_range = let_range.contains_range(ctx.frange.range);
42 if !cursor_in_range { 42 if !cursor_in_range {
43 return None; 43 return None;
44 } 44 }
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 0621487e8..03806724a 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode, NameOwner}, 2 ast::{self, AstNode, NameOwner},
3 TextUnit, 3 TextSize,
4}; 4};
5use stdx::format_to; 5use stdx::format_to;
6 6
@@ -65,7 +65,7 @@ impl From<{0}> for {1} {{
65 variant_name 65 variant_name
66 ); 66 );
67 edit.insert(start_offset, buf); 67 edit.insert(start_offset, buf);
68 edit.set_cursor(start_offset + TextUnit::of_str("\n\n")); 68 edit.set_cursor(start_offset + TextSize::of("\n\n"));
69 }, 69 },
70 ) 70 )
71} 71}
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index f185cffdb..7a8f5705f 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 SyntaxKind, SyntaxNode, TextUnit, 3 SyntaxKind, SyntaxNode, TextSize,
4}; 4};
5 5
6use crate::{Assist, AssistCtx, AssistFile, AssistId}; 6use crate::{Assist, AssistCtx, AssistFile, AssistId};
@@ -69,8 +69,8 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
69} 69}
70 70
71struct FunctionTemplate { 71struct FunctionTemplate {
72 insert_offset: TextUnit, 72 insert_offset: TextSize,
73 cursor_offset: TextUnit, 73 cursor_offset: TextSize,
74 fn_def: ast::SourceFile, 74 fn_def: ast::SourceFile,
75 file: AssistFile, 75 file: AssistFile,
76} 76}
@@ -129,7 +129,7 @@ impl FunctionBuilder {
129 let fn_def = indent_once.increase_indent(fn_def); 129 let fn_def = indent_once.increase_indent(fn_def);
130 let fn_def = ast::make::add_trailing_newlines(1, fn_def); 130 let fn_def = ast::make::add_trailing_newlines(1, fn_def);
131 let fn_def = indent.increase_indent(fn_def); 131 let fn_def = indent.increase_indent(fn_def);
132 (fn_def, it.syntax().text_range().start() + TextUnit::from_usize(1)) 132 (fn_def, it.syntax().text_range().start() + TextSize::from_usize(1))
133 } 133 }
134 }; 134 };
135 135
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
index 6622eadb2..d26f8b93d 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode, NameOwner, TypeParamsOwner}, 2 ast::{self, AstNode, NameOwner, TypeParamsOwner},
3 TextUnit, 3 TextSize,
4}; 4};
5use stdx::{format_to, SepBy}; 5use stdx::{format_to, SepBy};
6 6
@@ -51,7 +51,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
51 format_to!(buf, "<{}>", generic_params) 51 format_to!(buf, "<{}>", generic_params)
52 } 52 }
53 buf.push_str(" {\n"); 53 buf.push_str(" {\n");
54 edit.set_cursor(start_offset + TextUnit::of_str(&buf)); 54 edit.set_cursor(start_offset + TextSize::of(&buf));
55 buf.push_str("\n}"); 55 buf.push_str("\n}");
56 edit.insert(start_offset, buf); 56 edit.insert(start_offset, buf);
57 }) 57 })
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 240b19fa3..0698cce88 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 ast::{ 3 ast::{
4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, 4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
5 }, 5 },
6 TextUnit, T, 6 TextSize, T,
7}; 7};
8use stdx::{format_to, SepBy}; 8use stdx::{format_to, SepBy};
9 9
@@ -77,16 +77,16 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
77 .text_range() 77 .text_range()
78 .end(); 78 .end();
79 79
80 Some((start, TextUnit::from_usize(1))) 80 Some((start, TextSize::from_usize(1)))
81 }) 81 })
82 .unwrap_or_else(|| { 82 .unwrap_or_else(|| {
83 buf = generate_impl_text(&strukt, &buf); 83 buf = generate_impl_text(&strukt, &buf);
84 let start = strukt.syntax().text_range().end(); 84 let start = strukt.syntax().text_range().end();
85 85
86 (start, TextUnit::from_usize(3)) 86 (start, TextSize::from_usize(3))
87 }); 87 });
88 88
89 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset); 89 edit.set_cursor(start_offset + TextSize::of(&buf) - end_offset);
90 edit.insert(start_offset, buf); 90 edit.insert(start_offset, buf);
91 }) 91 })
92} 92}
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs
index 239807e24..260b9e073 100644
--- a/crates/ra_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ra_assists/src/handlers/apply_demorgan.rs
@@ -26,7 +26,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
26 let op = expr.op_kind()?; 26 let op = expr.op_kind()?;
27 let op_range = expr.op_token()?.text_range(); 27 let op_range = expr.op_token()?.text_range();
28 let opposite_op = opposite_logic_op(op)?; 28 let opposite_op = opposite_logic_op(op)?;
29 let cursor_in_range = ctx.frange.range.is_subrange(&op_range); 29 let cursor_in_range = op_range.contains_range(ctx.frange.range);
30 if !cursor_in_range { 30 if !cursor_in_range {
31 return None; 31 return None;
32 } 32 }
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index cd6d1ee6c..44f6a1dae 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, 5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
6 WHITESPACE, 6 WHITESPACE,
7 }, 7 },
8 SyntaxNode, TextUnit, T, 8 SyntaxNode, TextSize, T,
9}; 9};
10 10
11use crate::{Assist, AssistCtx, AssistId}; 11use crate::{Assist, AssistCtx, AssistId};
@@ -67,7 +67,7 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> {
67 }) 67 })
68} 68}
69 69
70fn vis_offset(node: &SyntaxNode) -> TextUnit { 70fn vis_offset(node: &SyntaxNode) -> TextSize {
71 node.children_with_tokens() 71 node.children_with_tokens()
72 .skip_while(|it| match it.kind() { 72 .skip_while(|it| match it.kind() {
73 WHITESPACE | COMMENT | ATTR => true, 73 WHITESPACE | COMMENT | ATTR => true,
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs
index bfcc09e90..8030efb35 100644
--- a/crates/ra_assists/src/handlers/flip_binexpr.rs
+++ b/crates/ra_assists/src/handlers/flip_binexpr.rs
@@ -23,7 +23,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> {
23 let rhs = expr.rhs()?.syntax().clone(); 23 let rhs = expr.rhs()?.syntax().clone();
24 let op_range = expr.op_token()?.text_range(); 24 let op_range = expr.op_token()?.text_range();
25 // The assist should be applied only if the cursor is on the operator 25 // The assist should be applied only if the cursor is on the operator
26 let cursor_in_range = ctx.frange.range.is_subrange(&op_range); 26 let cursor_in_range = op_range.contains_range(ctx.frange.range);
27 if !cursor_in_range { 27 if !cursor_in_range {
28 return None; 28 return None;
29 } 29 }
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index c4fb425b0..f5702f6e0 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -52,7 +52,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
52 .next_sibling_or_token() 52 .next_sibling_or_token()
53 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone())) 53 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone()))
54 { 54 {
55 TextRange::from_to( 55 TextRange::new(
56 let_stmt.syntax().text_range().start(), 56 let_stmt.syntax().text_range().start(),
57 whitespace.syntax().text_range().end(), 57 whitespace.syntax().text_range().end(),
58 ) 58 )
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index 8c09e6bcd..eda9ac296 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, 4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
5 WHITESPACE, 5 WHITESPACE,
6 }, 6 },
7 SyntaxNode, TextUnit, 7 SyntaxNode, TextSize,
8}; 8};
9use stdx::format_to; 9use stdx::format_to;
10use test_utils::tested_by; 10use test_utils::tested_by;
@@ -47,10 +47,10 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
47 47
48 let cursor_offset = if wrap_in_block { 48 let cursor_offset = if wrap_in_block {
49 buf.push_str("{ let var_name = "); 49 buf.push_str("{ let var_name = ");
50 TextUnit::of_str("{ let ") 50 TextSize::of("{ let ")
51 } else { 51 } else {
52 buf.push_str("let var_name = "); 52 buf.push_str("let var_name = ");
53 TextUnit::of_str("let ") 53 TextSize::of("let ")
54 }; 54 };
55 format_to!(buf, "{}", expr.syntax()); 55 format_to!(buf, "{}", expr.syntax());
56 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); 56 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone());
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs
index 4c5716868..682e08512 100644
--- a/crates/ra_assists/src/handlers/invert_if.rs
+++ b/crates/ra_assists/src/handlers/invert_if.rs
@@ -28,7 +28,7 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
28 let if_keyword = ctx.find_token_at_offset(T![if])?; 28 let if_keyword = ctx.find_token_at_offset(T![if])?;
29 let expr = ast::IfExpr::cast(if_keyword.parent())?; 29 let expr = ast::IfExpr::cast(if_keyword.parent())?;
30 let if_range = if_keyword.text_range(); 30 let if_range = if_keyword.text_range();
31 let cursor_in_range = ctx.frange.range.is_subrange(&if_range); 31 let cursor_in_range = if_range.contains_range(ctx.frange.range);
32 if !cursor_in_range { 32 if !cursor_in_range {
33 return None; 33 return None;
34 } 34 }
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index eb967ab92..cd0416f01 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::neighbor, 4 algo::neighbor,
5 ast::{self, AstNode}, 5 ast::{self, AstNode},
6 Direction, TextUnit, 6 Direction, TextSize,
7}; 7};
8 8
9use crate::{Assist, AssistCtx, AssistId, TextRange}; 9use crate::{Assist, AssistCtx, AssistId, TextRange};
@@ -42,8 +42,8 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
42 let current_text_range = current_arm.syntax().text_range(); 42 let current_text_range = current_arm.syntax().text_range();
43 43
44 enum CursorPos { 44 enum CursorPos {
45 InExpr(TextUnit), 45 InExpr(TextSize),
46 InPat(TextUnit), 46 InPat(TextSize),
47 } 47 }
48 let cursor_pos = ctx.frange.range.start(); 48 let cursor_pos = ctx.frange.range.start();
49 let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) { 49 let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) {
@@ -89,10 +89,10 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
89 89
90 edit.target(current_text_range); 90 edit.target(current_text_range);
91 edit.set_cursor(match cursor_pos { 91 edit.set_cursor(match cursor_pos {
92 CursorPos::InExpr(back_offset) => start + TextUnit::from_usize(arm.len()) - back_offset, 92 CursorPos::InExpr(back_offset) => start + TextSize::from_usize(arm.len()) - back_offset,
93 CursorPos::InPat(offset) => offset, 93 CursorPos::InPat(offset) => offset,
94 }); 94 });
95 edit.replace(TextRange::from_to(start, end), arm); 95 edit.replace(TextRange::new(start, end), arm);
96 }) 96 })
97} 97}
98 98
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index 1cc498638..d5ccdd91c 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -1,7 +1,7 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast, 2 ast,
3 ast::{AstNode, AstToken, IfExpr, MatchArm}, 3 ast::{AstNode, AstToken, IfExpr, MatchArm},
4 TextUnit, 4 TextSize,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
@@ -49,16 +49,16 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
49 edit.delete(ele); 49 edit.delete(ele);
50 ele.len() 50 ele.len()
51 } else { 51 } else {
52 TextUnit::from(0) 52 TextSize::from(0)
53 } 53 }
54 } 54 }
55 _ => TextUnit::from(0), 55 _ => TextSize::from(0),
56 }; 56 };
57 57
58 edit.delete(guard.syntax().text_range()); 58 edit.delete(guard.syntax().text_range());
59 edit.replace_node_and_indent(arm_expr.syntax(), buf); 59 edit.replace_node_and_indent(arm_expr.syntax(), buf);
60 edit.set_cursor( 60 edit.set_cursor(
61 arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount, 61 arm_expr.syntax().text_range().start() + TextSize::from(3) - offseting_amount,
62 ); 62 );
63 }) 63 })
64} 64}
@@ -123,7 +123,7 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
123 } 123 }
124 124
125 edit.insert(match_pat.syntax().text_range().end(), buf); 125 edit.insert(match_pat.syntax().text_range().end(), buf);
126 edit.set_cursor(match_pat.syntax().text_range().end() + TextUnit::from(1)); 126 edit.set_cursor(match_pat.syntax().text_range().end() + TextSize::from(1));
127 }, 127 },
128 ) 128 )
129} 129}
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index 7e4b83f13..567400b9c 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -2,7 +2,7 @@ use ra_syntax::{
2 ast::{self, HasStringValue}, 2 ast::{self, HasStringValue},
3 AstToken, 3 AstToken,
4 SyntaxKind::{RAW_STRING, STRING}, 4 SyntaxKind::{RAW_STRING, STRING},
5 TextUnit, 5 TextSize,
6}; 6};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
@@ -81,7 +81,7 @@ pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> {
81 let token = ctx.find_token_at_offset(RAW_STRING)?; 81 let token = ctx.find_token_at_offset(RAW_STRING)?;
82 ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| { 82 ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| {
83 edit.target(token.text_range()); 83 edit.target(token.text_range());
84 edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); 84 edit.insert(token.text_range().start() + TextSize::of('r'), "#");
85 edit.insert(token.text_range().end(), "#"); 85 edit.insert(token.text_range().end(), "#");
86 }) 86 })
87} 87}
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs
index 5085649b4..4e5eb4350 100644
--- a/crates/ra_assists/src/handlers/remove_dbg.rs
+++ b/crates/ra_assists/src/handlers/remove_dbg.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 TextUnit, T, 3 TextSize, T,
4}; 4};
5 5
6use crate::{Assist, AssistCtx, AssistId}; 6use crate::{Assist, AssistCtx, AssistId};
@@ -38,9 +38,9 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> {
38 let offset_start = file_range 38 let offset_start = file_range
39 .start() 39 .start()
40 .checked_sub(macro_range.start()) 40 .checked_sub(macro_range.start())
41 .unwrap_or_else(|| TextUnit::from(0)); 41 .unwrap_or_else(|| TextSize::from(0));
42 42
43 let dbg_size = TextUnit::of_str("dbg!("); 43 let dbg_size = TextSize::of("dbg!(");
44 44
45 if offset_start > dbg_size { 45 if offset_start > dbg_size {
46 file_range.start() - dbg_size 46 file_range.start() - dbg_size
@@ -53,7 +53,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> {
53 let macro_args = macro_call.token_tree()?.syntax().clone(); 53 let macro_args = macro_call.token_tree()?.syntax().clone();
54 54
55 let text = macro_args.text(); 55 let text = macro_args.text();
56 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); 56 let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
57 text.slice(without_parens).to_string() 57 text.slice(without_parens).to_string()
58 }; 58 };
59 59
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs
index 6884830eb..e598023b2 100644
--- a/crates/ra_assists/src/handlers/remove_mut.rs
+++ b/crates/ra_assists/src/handlers/remove_mut.rs
@@ -27,6 +27,6 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> {
27 27
28 ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", |edit| { 28 ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", |edit| {
29 edit.set_cursor(delete_from); 29 edit.set_cursor(delete_from);
30 edit.delete(TextRange::from_to(delete_from, delete_to)); 30 edit.delete(TextRange::new(delete_from, delete_to));
31 }) 31 })
32} 32}
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index 94f5d6c50..2f02df303 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -43,7 +43,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist>
43 if let Some(last) = path.segment() { 43 if let Some(last) = path.segment() {
44 // Here we are assuming the assist will provide a correct use statement 44 // Here we are assuming the assist will provide a correct use statement
45 // so we can delete the path qualifier 45 // so we can delete the path qualifier
46 edit.delete(TextRange::from_to( 46 edit.delete(TextRange::new(
47 path.syntax().text_range().start(), 47 path.syntax().text_range().start(),
48 last.syntax().text_range().start(), 48 last.syntax().text_range().start(),
49 )); 49 ));
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index ccc95735f..3ffbe4c51 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -19,7 +19,7 @@ pub mod ast_transform;
19 19
20use ra_db::{FileId, FileRange}; 20use ra_db::{FileId, FileRange};
21use ra_ide_db::RootDatabase; 21use ra_ide_db::RootDatabase;
22use ra_syntax::{TextRange, TextUnit}; 22use ra_syntax::{TextRange, TextSize};
23use ra_text_edit::TextEdit; 23use ra_text_edit::TextEdit;
24 24
25pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler}; 25pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler};
@@ -51,7 +51,7 @@ impl AssistLabel {
51#[derive(Debug, Clone)] 51#[derive(Debug, Clone)]
52pub struct AssistAction { 52pub struct AssistAction {
53 pub edit: TextEdit, 53 pub edit: TextEdit,
54 pub cursor_position: Option<TextUnit>, 54 pub cursor_position: Option<TextSize>,
55 // FIXME: This belongs to `AssistLabel` 55 // FIXME: This belongs to `AssistLabel`
56 pub target: Option<TextRange>, 56 pub target: Option<TextRange>,
57 pub file: AssistFile, 57 pub file: AssistFile,
@@ -104,7 +104,7 @@ pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssi
104 .flat_map(|it| it.0) 104 .flat_map(|it| it.0)
105 .map(|it| it.into_resolved().unwrap()) 105 .map(|it| it.into_resolved().unwrap())
106 .collect::<Vec<_>>(); 106 .collect::<Vec<_>>();
107 a.sort_by_key(|it| it.action.target.map_or(TextUnit::from(!0u32), |it| it.len())); 107 a.sort_by_key(|it| it.action.target.map_or(TextSize::from(!0u32), |it| it.len()));
108 a 108 a
109} 109}
110 110
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index a06f59c14..fd4280de2 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -6,7 +6,7 @@ pub mod fixture;
6use std::{panic, sync::Arc}; 6use std::{panic, sync::Arc};
7 7
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; 9use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize};
10 10
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
@@ -75,7 +75,7 @@ impl<T: salsa::Database> CheckCanceled for T {
75#[derive(Clone, Copy, Debug)] 75#[derive(Clone, Copy, Debug)]
76pub struct FilePosition { 76pub struct FilePosition {
77 pub file_id: FileId, 77 pub file_id: FileId,
78 pub offset: TextUnit, 78 pub offset: TextSize,
79} 79}
80 80
81#[derive(Clone, Copy, Debug)] 81#[derive(Clone, Copy, Debug)]
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 5d6edc45c..e09cf3185 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -14,7 +14,7 @@ use ra_db::{FileId, FileRange};
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{ 15use ra_syntax::{
16 algo::{find_node_at_offset, skip_trivia_token}, 16 algo::{find_node_at_offset, skip_trivia_token},
17 ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit, 17 ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
18}; 18};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
20 20
@@ -95,7 +95,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
95 let token = successors(Some(parent.with_value(token)), |token| { 95 let token = successors(Some(parent.with_value(token)), |token| {
96 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 96 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
97 let tt = macro_call.token_tree()?; 97 let tt = macro_call.token_tree()?;
98 if !token.value.text_range().is_subrange(&tt.syntax().text_range()) { 98 if !tt.syntax().text_range().contains_range(token.value.text_range()) {
99 return None; 99 return None;
100 } 100 }
101 let file_id = sa.expand(self.db, token.with_value(&macro_call))?; 101 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
@@ -114,7 +114,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
114 pub fn descend_node_at_offset<N: ast::AstNode>( 114 pub fn descend_node_at_offset<N: ast::AstNode>(
115 &self, 115 &self,
116 node: &SyntaxNode, 116 node: &SyntaxNode,
117 offset: TextUnit, 117 offset: TextSize,
118 ) -> Option<N> { 118 ) -> Option<N> {
119 // Handle macro token cases 119 // Handle macro token cases
120 node.token_at_offset(offset) 120 node.token_at_offset(offset)
@@ -142,7 +142,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
142 pub fn ancestors_at_offset_with_macros( 142 pub fn ancestors_at_offset_with_macros(
143 &self, 143 &self,
144 node: &SyntaxNode, 144 node: &SyntaxNode,
145 offset: TextUnit, 145 offset: TextSize,
146 ) -> impl Iterator<Item = SyntaxNode> + '_ { 146 ) -> impl Iterator<Item = SyntaxNode> + '_ {
147 node.token_at_offset(offset) 147 node.token_at_offset(offset)
148 .map(|token| self.ancestors_with_macros(token.parent())) 148 .map(|token| self.ancestors_with_macros(token.parent()))
@@ -154,7 +154,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
154 pub fn find_node_at_offset_with_macros<N: AstNode>( 154 pub fn find_node_at_offset_with_macros<N: AstNode>(
155 &self, 155 &self,
156 node: &SyntaxNode, 156 node: &SyntaxNode,
157 offset: TextUnit, 157 offset: TextSize,
158 ) -> Option<N> { 158 ) -> Option<N> {
159 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) 159 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
160 } 160 }
@@ -164,7 +164,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
164 pub fn find_node_at_offset_with_descend<N: AstNode>( 164 pub fn find_node_at_offset_with_descend<N: AstNode>(
165 &self, 165 &self,
166 node: &SyntaxNode, 166 node: &SyntaxNode,
167 offset: TextUnit, 167 offset: TextSize,
168 ) -> Option<N> { 168 ) -> Option<N> {
169 if let Some(it) = find_node_at_offset(&node, offset) { 169 if let Some(it) = find_node_at_offset(&node, offset) {
170 return Some(it); 170 return Some(it);
@@ -255,7 +255,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
255 SemanticsScope { db: self.db, resolver } 255 SemanticsScope { db: self.db, resolver }
256 } 256 }
257 257
258 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextUnit) -> SemanticsScope<'db, DB> { 258 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db, DB> {
259 let node = self.find_file(node.clone()); 259 let node = self.find_file(node.clone());
260 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; 260 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
261 SemanticsScope { db: self.db, resolver } 261 SemanticsScope { db: self.db, resolver }
@@ -271,7 +271,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
271 self.analyze2(src.as_ref(), None) 271 self.analyze2(src.as_ref(), None)
272 } 272 }
273 273
274 fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextUnit>) -> SourceAnalyzer { 274 fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextSize>) -> SourceAnalyzer {
275 let _p = profile("Semantics::analyze2"); 275 let _p = profile("Semantics::analyze2");
276 276
277 let container = match self.with_ctx(|ctx| ctx.find_container(src)) { 277 let container = match self.with_ctx(|ctx| ctx.find_container(src)) {
@@ -463,7 +463,7 @@ fn original_range_opt(
463 return None; 463 return None;
464 } 464 }
465 465
466 Some(first.with_value(first.value.text_range().extend_to(&last.value.text_range()))) 466 Some(first.with_value(first.value.text_range().cover(last.value.text_range())))
467 })?) 467 })?)
468} 468}
469 469
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 0ed6d0958..59a3a17d2 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -23,7 +23,7 @@ use hir_ty::{
23}; 23};
24use ra_syntax::{ 24use ra_syntax::{
25 ast::{self, AstNode}, 25 ast::{self, AstNode},
26 SyntaxNode, TextRange, TextUnit, 26 SyntaxNode, TextRange, TextSize,
27}; 27};
28 28
29use crate::{ 29use crate::{
@@ -50,7 +50,7 @@ impl SourceAnalyzer {
50 db: &dyn HirDatabase, 50 db: &dyn HirDatabase,
51 def: DefWithBodyId, 51 def: DefWithBodyId,
52 node: InFile<&SyntaxNode>, 52 node: InFile<&SyntaxNode>,
53 offset: Option<TextUnit>, 53 offset: Option<TextSize>,
54 ) -> SourceAnalyzer { 54 ) -> SourceAnalyzer {
55 let (body, source_map) = db.body_with_source_map(def); 55 let (body, source_map) = db.body_with_source_map(def);
56 let scopes = db.expr_scopes(def); 56 let scopes = db.expr_scopes(def);
@@ -318,7 +318,7 @@ fn scope_for_offset(
318 db: &dyn HirDatabase, 318 db: &dyn HirDatabase,
319 scopes: &ExprScopes, 319 scopes: &ExprScopes,
320 source_map: &BodySourceMap, 320 source_map: &BodySourceMap,
321 offset: InFile<TextUnit>, 321 offset: InFile<TextSize>,
322) -> Option<ScopeId> { 322) -> Option<ScopeId> {
323 scopes 323 scopes
324 .scope_by_expr() 324 .scope_by_expr()
@@ -354,7 +354,7 @@ fn adjust(
354 source_map: &BodySourceMap, 354 source_map: &BodySourceMap,
355 expr_range: TextRange, 355 expr_range: TextRange,
356 file_id: HirFileId, 356 file_id: HirFileId,
357 offset: TextUnit, 357 offset: TextSize,
358) -> Option<ScopeId> { 358) -> Option<ScopeId> {
359 let child_scopes = scopes 359 let child_scopes = scopes
360 .scope_by_expr() 360 .scope_by_expr()
@@ -369,15 +369,15 @@ fn adjust(
369 let node = source.value.to_node(&root); 369 let node = source.value.to_node(&root);
370 Some((node.syntax().text_range(), scope)) 370 Some((node.syntax().text_range(), scope))
371 }) 371 })
372 .filter(|(range, _)| { 372 .filter(|&(range, _)| {
373 range.start() <= offset && range.is_subrange(&expr_range) && *range != expr_range 373 range.start() <= offset && expr_range.contains_range(range) && range != expr_range
374 }); 374 });
375 375
376 child_scopes 376 child_scopes
377 .max_by(|(r1, _), (r2, _)| { 377 .max_by(|&(r1, _), &(r2, _)| {
378 if r2.is_subrange(&r1) { 378 if r1.contains_range(r2) {
379 std::cmp::Ordering::Greater 379 std::cmp::Ordering::Greater
380 } else if r1.is_subrange(&r2) { 380 } else if r2.contains_range(r1) {
381 std::cmp::Ordering::Less 381 std::cmp::Ordering::Less
382 } else { 382 } else {
383 r1.start().cmp(&r2.start()) 383 r1.start().cmp(&r2.start())
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 3da137f2e..2ccebda28 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -2,7 +2,7 @@
2use crate::db::AstDatabase; 2use crate::db::AstDatabase;
3use crate::{ 3use crate::{
4 ast::{self, AstToken, HasStringValue}, 4 ast::{self, AstToken, HasStringValue},
5 name, AstId, CrateId, MacroDefId, MacroDefKind, TextUnit, 5 name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize,
6}; 6};
7 7
8use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; 8use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId};
@@ -127,7 +127,7 @@ fn stringify_expand(
127 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 127 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
128 let macro_args = arg; 128 let macro_args = arg;
129 let text = macro_args.text(); 129 let text = macro_args.text();
130 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); 130 let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
131 text.slice(without_parens).to_string() 131 text.slice(without_parens).to_string()
132 }; 132 };
133 133
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 86299459f..754a0f005 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -22,7 +22,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, FileId};
22use ra_syntax::{ 22use ra_syntax::{
23 algo, 23 algo,
24 ast::{self, AstNode}, 24 ast::{self, AstNode},
25 SyntaxNode, SyntaxToken, TextUnit, 25 SyntaxNode, SyntaxToken, TextSize,
26}; 26};
27 27
28use crate::ast_id_map::FileAstId; 28use crate::ast_id_map::FileAstId;
@@ -348,7 +348,7 @@ impl<N: AstNode> AstId<N> {
348/// 348///
349/// * `InFile<SyntaxNode>` -- syntax node in a file 349/// * `InFile<SyntaxNode>` -- syntax node in a file
350/// * `InFile<ast::FnDef>` -- ast node in a file 350/// * `InFile<ast::FnDef>` -- ast node in a file
351/// * `InFile<TextUnit>` -- offset in a file 351/// * `InFile<TextSize>` -- offset in a file
352#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 352#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
353pub struct InFile<T> { 353pub struct InFile<T> {
354 pub file_id: HirFileId, 354 pub file_id: HirFileId,
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 846005baa..b6a96bb5c 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -117,7 +117,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
117 let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" }; 117 let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" };
118 format_to!( 118 format_to!(
119 buf, 119 buf,
120 "{}{} '{}': {}\n", 120 "{}{:?} '{}': {}\n",
121 macro_prefix, 121 macro_prefix,
122 range, 122 range,
123 ellipsize(text, 15), 123 ellipsize(text, 15),
@@ -134,7 +134,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
134 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; 134 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
135 format_to!( 135 format_to!(
136 buf, 136 buf,
137 "{}{}: expected {}, got {}\n", 137 "{}{:?}: expected {}, got {}\n",
138 macro_prefix, 138 macro_prefix,
139 range, 139 range,
140 mismatch.expected.display(&db), 140 mismatch.expected.display(&db),
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 5da254a6e..780a03c13 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -126,7 +126,7 @@ impl FnCallNode {
126 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 126 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
127 ast::MethodCallExpr(it) => { 127 ast::MethodCallExpr(it) => {
128 let arg_list = it.arg_list()?; 128 let arg_list = it.arg_list()?;
129 if !syntax.text_range().is_subrange(&arg_list.syntax().text_range()) { 129 if !arg_list.syntax().text_range().contains_range(syntax.text_range()) {
130 return None; 130 return None;
131 } 131 }
132 Some(FnCallNode::MethodCallExpr(it)) 132 Some(FnCallNode::MethodCallExpr(it))
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index adefb290e..306ce96dc 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -97,7 +97,7 @@ fn is_in_loop_body(leaf: &SyntaxToken) -> bool {
97 } 97 }
98 }; 98 };
99 if let Some(body) = loop_body { 99 if let Some(body) = loop_body {
100 if leaf.text_range().is_subrange(&body.syntax().text_range()) { 100 if body.syntax().text_range().contains_range(leaf.text_range()) {
101 return true; 101 return true;
102 } 102 }
103 } 103 }
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 8d397b0fe..d6a37d720 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -2,7 +2,7 @@
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 TextRange, TextUnit, 5 TextRange, TextSize,
6}; 6};
7use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
8 8
@@ -115,7 +115,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
115fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { 115fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
116 if receiver_is_ambiguous_float_literal { 116 if receiver_is_ambiguous_float_literal {
117 let text = receiver.syntax().text(); 117 let text = receiver.syntax().text();
118 let without_dot = ..text.len() - TextUnit::of_char('.'); 118 let without_dot = ..text.len() - TextSize::of('.');
119 text.slice(without_dot).to_string() 119 text.slice(without_dot).to_string()
120 } else { 120 } else {
121 receiver.to_string() 121 receiver.to_string()
@@ -143,7 +143,7 @@ fn postfix_snippet(
143 let edit = { 143 let edit = {
144 let receiver_syntax = receiver.syntax(); 144 let receiver_syntax = receiver.syntax();
145 let receiver_range = ctx.sema.original_range(receiver_syntax).range; 145 let receiver_range = ctx.sema.original_range(receiver_syntax).range;
146 let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); 146 let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end());
147 TextEdit::replace(delete_range, snippet.to_string()) 147 TextEdit::replace(delete_range, snippet.to_string())
148 }; 148 };
149 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 149 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index c39943252..e2a8c59cd 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -141,7 +141,7 @@ fn add_function_impl(
141 } else { 141 } else {
142 CompletionItemKind::Function 142 CompletionItemKind::Function
143 }; 143 };
144 let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); 144 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
145 145
146 match ctx.config.snippet_cap { 146 match ctx.config.snippet_cap {
147 Some(cap) => { 147 Some(cap) => {
@@ -167,7 +167,7 @@ fn add_type_alias_impl(
167 167
168 let snippet = format!("type {} = ", alias_name); 168 let snippet = format!("type {} = ", alias_name);
169 169
170 let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end()); 170 let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());
171 171
172 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 172 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
173 .text_edit(TextEdit::replace(range, snippet)) 173 .text_edit(TextEdit::replace(range, snippet))
@@ -189,7 +189,7 @@ fn add_const_impl(
189 let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); 189 let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);
190 190
191 let range = 191 let range =
192 TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end()); 192 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
193 193
194 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 194 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
195 .text_edit(TextEdit::replace(range, snippet)) 195 .text_edit(TextEdit::replace(range, snippet))
@@ -216,7 +216,7 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
216 .map_or(const_end, |f| f.text_range().start()); 216 .map_or(const_end, |f| f.text_range().start());
217 217
218 let len = end - start; 218 let len = end - start;
219 let range = TextRange::from_to(0.into(), len); 219 let range = TextRange::new(0.into(), len);
220 220
221 let syntax = const_.syntax().text().slice(range).to_string(); 221 let syntax = const_.syntax().text().slice(range).to_string();
222 222
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 37880448a..5f2797e41 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
8 ast, AstNode, 8 ast, AstNode,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextUnit, 10 SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12use ra_text_edit::AtomTextEdit; 12use ra_text_edit::AtomTextEdit;
13 13
@@ -20,7 +20,7 @@ pub(crate) struct CompletionContext<'a> {
20 pub(super) sema: Semantics<'a, RootDatabase>, 20 pub(super) sema: Semantics<'a, RootDatabase>,
21 pub(super) db: &'a RootDatabase, 21 pub(super) db: &'a RootDatabase,
22 pub(super) config: &'a CompletionConfig, 22 pub(super) config: &'a CompletionConfig,
23 pub(super) offset: TextUnit, 23 pub(super) offset: TextSize,
24 /// The token before the cursor, in the original file. 24 /// The token before the cursor, in the original file.
25 pub(super) original_token: SyntaxToken, 25 pub(super) original_token: SyntaxToken,
26 /// The token before the cursor, in the macro-expanded file. 26 /// The token before the cursor, in the macro-expanded file.
@@ -167,7 +167,7 @@ impl<'a> CompletionContext<'a> {
167 match self.token.kind() { 167 match self.token.kind() {
168 // workaroud when completion is triggered by trigger characters. 168 // workaroud when completion is triggered by trigger characters.
169 IDENT => self.original_token.text_range(), 169 IDENT => self.original_token.text_range(),
170 _ => TextRange::offset_len(self.offset, 0.into()), 170 _ => TextRange::empty(self.offset),
171 } 171 }
172 } 172 }
173 173
@@ -190,7 +190,7 @@ impl<'a> CompletionContext<'a> {
190 &mut self, 190 &mut self,
191 original_file: &SyntaxNode, 191 original_file: &SyntaxNode,
192 file_with_fake_ident: SyntaxNode, 192 file_with_fake_ident: SyntaxNode,
193 offset: TextUnit, 193 offset: TextSize,
194 ) { 194 ) {
195 // First, let's try to complete a reference to some declaration. 195 // First, let's try to complete a reference to some declaration.
196 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) { 196 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
@@ -224,7 +224,8 @@ impl<'a> CompletionContext<'a> {
224 } 224 }
225 if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) { 225 if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) {
226 if let Some(pat) = let_stmt.pat() { 226 if let Some(pat) = let_stmt.pat() {
227 if bind_pat.syntax().text_range().is_subrange(&pat.syntax().text_range()) { 227 if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range())
228 {
228 self.is_pat_binding_or_const = false; 229 self.is_pat_binding_or_const = false;
229 } 230 }
230 } 231 }
@@ -246,7 +247,7 @@ impl<'a> CompletionContext<'a> {
246 &mut self, 247 &mut self,
247 original_file: &SyntaxNode, 248 original_file: &SyntaxNode,
248 name_ref: ast::NameRef, 249 name_ref: ast::NameRef,
249 offset: TextUnit, 250 offset: TextSize,
250 ) { 251 ) {
251 self.name_ref_syntax = 252 self.name_ref_syntax =
252 find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); 253 find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index e7e201709..adfb1b9b2 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -171,7 +171,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
171 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { 171 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] {
172 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); 172 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
173 let end = use_tree_list_node.text_range().end(); 173 let end = use_tree_list_node.text_range().end();
174 let range = TextRange::from_to(start, end); 174 let range = TextRange::new(start, end);
175 return Some(TextEdit::delete(range)); 175 return Some(TextEdit::delete(range));
176 } 176 }
177 None 177 None
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index 753d2ef6a..9f329b5d3 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9 ast::{self, AstNode, AstToken}, 9 ast::{self, AstNode, AstToken},
10 Direction, NodeOrToken, 10 Direction, NodeOrToken,
11 SyntaxKind::{self, *}, 11 SyntaxKind::{self, *},
12 SyntaxNode, SyntaxToken, TextRange, TextUnit, TokenAtOffset, T, 12 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, T,
13}; 13};
14 14
15use crate::FileRange; 15use crate::FileRange;
@@ -121,10 +121,10 @@ fn extend_tokens_from_range(
121 let mut first_token = skip_trivia_token(first_token, Direction::Next)?; 121 let mut first_token = skip_trivia_token(first_token, Direction::Next)?;
122 let mut last_token = skip_trivia_token(last_token, Direction::Prev)?; 122 let mut last_token = skip_trivia_token(last_token, Direction::Prev)?;
123 123
124 while !first_token.text_range().is_subrange(&original_range) { 124 while !original_range.contains_range(first_token.text_range()) {
125 first_token = skip_trivia_token(first_token.next_token()?, Direction::Next)?; 125 first_token = skip_trivia_token(first_token.next_token()?, Direction::Next)?;
126 } 126 }
127 while !last_token.text_range().is_subrange(&original_range) { 127 while !original_range.contains_range(last_token.text_range()) {
128 last_token = skip_trivia_token(last_token.prev_token()?, Direction::Prev)?; 128 last_token = skip_trivia_token(last_token.prev_token()?, Direction::Prev)?;
129 } 129 }
130 130
@@ -161,8 +161,8 @@ fn extend_tokens_from_range(
161 .take_while(validate) 161 .take_while(validate)
162 .last()?; 162 .last()?;
163 163
164 let range = first.text_range().extend_to(&last.text_range()); 164 let range = first.text_range().cover(last.text_range());
165 if original_range.is_subrange(&range) && original_range != range { 165 if range.contains_range(original_range) && original_range != range {
166 Some(range) 166 Some(range)
167 } else { 167 } else {
168 None 168 None
@@ -176,7 +176,7 @@ fn shallowest_node(node: &SyntaxNode) -> SyntaxNode {
176 176
177fn extend_single_word_in_comment_or_string( 177fn extend_single_word_in_comment_or_string(
178 leaf: &SyntaxToken, 178 leaf: &SyntaxToken,
179 offset: TextUnit, 179 offset: TextSize,
180) -> Option<TextRange> { 180) -> Option<TextRange> {
181 let text: &str = leaf.text(); 181 let text: &str = leaf.text();
182 let cursor_position: u32 = (offset - leaf.text_range().start()).into(); 182 let cursor_position: u32 = (offset - leaf.text_range().start()).into();
@@ -190,10 +190,10 @@ fn extend_single_word_in_comment_or_string(
190 let start_idx = before.rfind(non_word_char)? as u32; 190 let start_idx = before.rfind(non_word_char)? as u32;
191 let end_idx = after.find(non_word_char).unwrap_or_else(|| after.len()) as u32; 191 let end_idx = after.find(non_word_char).unwrap_or_else(|| after.len()) as u32;
192 192
193 let from: TextUnit = (start_idx + 1).into(); 193 let from: TextSize = (start_idx + 1).into();
194 let to: TextUnit = (cursor_position + end_idx).into(); 194 let to: TextSize = (cursor_position + end_idx).into();
195 195
196 let range = TextRange::from_to(from, to); 196 let range = TextRange::new(from, to);
197 if range.is_empty() { 197 if range.is_empty() {
198 None 198 None
199 } else { 199 } else {
@@ -201,24 +201,24 @@ fn extend_single_word_in_comment_or_string(
201 } 201 }
202} 202}
203 203
204fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange { 204fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange {
205 let ws_text = ws.text(); 205 let ws_text = ws.text();
206 let suffix = TextRange::from_to(offset, ws.text_range().end()) - ws.text_range().start(); 206 let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start();
207 let prefix = TextRange::from_to(ws.text_range().start(), offset) - ws.text_range().start(); 207 let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start();
208 let ws_suffix = &ws_text.as_str()[suffix]; 208 let ws_suffix = &ws_text.as_str()[suffix];
209 let ws_prefix = &ws_text.as_str()[prefix]; 209 let ws_prefix = &ws_text.as_str()[prefix];
210 if ws_text.contains('\n') && !ws_suffix.contains('\n') { 210 if ws_text.contains('\n') && !ws_suffix.contains('\n') {
211 if let Some(node) = ws.next_sibling_or_token() { 211 if let Some(node) = ws.next_sibling_or_token() {
212 let start = match ws_prefix.rfind('\n') { 212 let start = match ws_prefix.rfind('\n') {
213 Some(idx) => ws.text_range().start() + TextUnit::from((idx + 1) as u32), 213 Some(idx) => ws.text_range().start() + TextSize::from((idx + 1) as u32),
214 None => node.text_range().start(), 214 None => node.text_range().start(),
215 }; 215 };
216 let end = if root.text().char_at(node.text_range().end()) == Some('\n') { 216 let end = if root.text().char_at(node.text_range().end()) == Some('\n') {
217 node.text_range().end() + TextUnit::of_char('\n') 217 node.text_range().end() + TextSize::of('\n')
218 } else { 218 } else {
219 node.text_range().end() 219 node.text_range().end()
220 }; 220 };
221 return TextRange::from_to(start, end); 221 return TextRange::new(start, end);
222 } 222 }
223 } 223 }
224 ws.text_range() 224 ws.text_range()
@@ -270,13 +270,10 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
270 .filter(|node| is_single_line_ws(node)) 270 .filter(|node| is_single_line_ws(node))
271 .unwrap_or(delimiter_node); 271 .unwrap_or(delimiter_node);
272 272
273 return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end())); 273 return Some(TextRange::new(node.text_range().start(), final_node.text_range().end()));
274 } 274 }
275 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) { 275 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) {
276 return Some(TextRange::from_to( 276 return Some(TextRange::new(delimiter_node.text_range().start(), node.text_range().end()));
277 delimiter_node.text_range().start(),
278 node.text_range().end(),
279 ));
280 } 277 }
281 278
282 None 279 None
@@ -286,10 +283,7 @@ fn extend_comments(comment: ast::Comment) -> Option<TextRange> {
286 let prev = adj_comments(&comment, Direction::Prev); 283 let prev = adj_comments(&comment, Direction::Prev);
287 let next = adj_comments(&comment, Direction::Next); 284 let next = adj_comments(&comment, Direction::Next);
288 if prev != next { 285 if prev != next {
289 Some(TextRange::from_to( 286 Some(TextRange::new(prev.syntax().text_range().start(), next.syntax().text_range().end()))
290 prev.syntax().text_range().start(),
291 next.syntax().text_range().end(),
292 ))
293 } else { 287 } else {
294 None 288 None
295 } 289 }
diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs
index 4eeb76d14..034c4c7d4 100644
--- a/crates/ra_ide/src/folding_ranges.rs
+++ b/crates/ra_ide/src/folding_ranges.rs
@@ -141,7 +141,7 @@ fn contiguous_range_for_group_unless(
141 } 141 }
142 142
143 if first != &last { 143 if first != &last {
144 Some(TextRange::from_to(first.text_range().start(), last.text_range().end())) 144 Some(TextRange::new(first.text_range().start(), last.text_range().end()))
145 } else { 145 } else {
146 // The group consists of only one element, therefore it cannot be folded 146 // The group consists of only one element, therefore it cannot be folded
147 None 147 None
@@ -187,7 +187,7 @@ fn contiguous_range_for_comment(
187 } 187 }
188 188
189 if first != last { 189 if first != last {
190 Some(TextRange::from_to( 190 Some(TextRange::new(
191 first.syntax().text_range().start(), 191 first.syntax().text_range().start(),
192 last.syntax().text_range().end(), 192 last.syntax().text_range().end(),
193 )) 193 ))
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index a31187994..fcc2ab7fb 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -275,7 +275,7 @@ mod tests {
275 ", 275 ",
276 ); 276 );
277 let hover = analysis.hover(position).unwrap().unwrap(); 277 let hover = analysis.hover(position).unwrap().unwrap();
278 assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into())); 278 assert_eq!(hover.range, TextRange::new(95.into(), 100.into()));
279 assert_eq!(trim_markup_opt(hover.info.first()), Some("u32")); 279 assert_eq!(trim_markup_opt(hover.info.first()), Some("u32"));
280 } 280 }
281 281
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs
index 7d70dab9c..040846ec3 100644
--- a/crates/ra_ide/src/join_lines.rs
+++ b/crates/ra_ide/src/join_lines.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken},
8 Direction, NodeOrToken, SourceFile, 8 Direction, NodeOrToken, SourceFile,
9 SyntaxKind::{self, WHITESPACE}, 9 SyntaxKind::{self, WHITESPACE},
10 SyntaxNode, SyntaxToken, TextRange, TextUnit, T, 10 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
11}; 11};
12use ra_text_edit::{TextEdit, TextEditBuilder}; 12use ra_text_edit::{TextEdit, TextEditBuilder};
13 13
@@ -19,7 +19,7 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
19 None => return TextEditBuilder::default().finish(), 19 None => return TextEditBuilder::default().finish(),
20 Some(pos) => pos, 20 Some(pos) => pos,
21 }; 21 };
22 TextRange::offset_len(range.start() + pos, TextUnit::of_char('\n')) 22 TextRange::at(range.start() + pos, TextSize::of('\n'))
23 } else { 23 } else {
24 range 24 range
25 }; 25 };
@@ -30,13 +30,13 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
30 }; 30 };
31 let mut edit = TextEditBuilder::default(); 31 let mut edit = TextEditBuilder::default();
32 for token in node.descendants_with_tokens().filter_map(|it| it.into_token()) { 32 for token in node.descendants_with_tokens().filter_map(|it| it.into_token()) {
33 let range = match range.intersection(&token.text_range()) { 33 let range = match range.intersect(token.text_range()) {
34 Some(range) => range, 34 Some(range) => range,
35 None => continue, 35 None => continue,
36 } - token.text_range().start(); 36 } - token.text_range().start();
37 let text = token.text(); 37 let text = token.text();
38 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { 38 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
39 let pos: TextUnit = (pos as u32).into(); 39 let pos: TextSize = (pos as u32).into();
40 let off = token.text_range().start() + range.start() + pos; 40 let off = token.text_range().start() + range.start() + pos;
41 if !edit.invalidates_offset(off) { 41 if !edit.invalidates_offset(off) {
42 remove_newline(&mut edit, &token, off); 42 remove_newline(&mut edit, &token, off);
@@ -47,16 +47,16 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
47 edit.finish() 47 edit.finish()
48} 48}
49 49
50fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextUnit) { 50fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) {
51 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { 51 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 {
52 // The node is either the first or the last in the file 52 // The node is either the first or the last in the file
53 let suff = &token.text()[TextRange::from_to( 53 let suff = &token.text()[TextRange::new(
54 offset - token.text_range().start() + TextUnit::of_char('\n'), 54 offset - token.text_range().start() + TextSize::of('\n'),
55 TextUnit::of_str(token.text()), 55 TextSize::of(token.text().as_str()),
56 )]; 56 )];
57 let spaces = suff.bytes().take_while(|&b| b == b' ').count(); 57 let spaces = suff.bytes().take_while(|&b| b == b' ').count();
58 58
59 edit.replace(TextRange::offset_len(offset, ((spaces + 1) as u32).into()), " ".to_string()); 59 edit.replace(TextRange::at(offset, ((spaces + 1) as u32).into()), " ".to_string());
60 return; 60 return;
61 } 61 }
62 62
@@ -65,7 +65,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
65 let next = token.next_sibling_or_token().unwrap(); 65 let next = token.next_sibling_or_token().unwrap();
66 if is_trailing_comma(prev.kind(), next.kind()) { 66 if is_trailing_comma(prev.kind(), next.kind()) {
67 // Removes: trailing comma, newline (incl. surrounding whitespace) 67 // Removes: trailing comma, newline (incl. surrounding whitespace)
68 edit.delete(TextRange::from_to(prev.text_range().start(), token.text_range().end())); 68 edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end()));
69 return; 69 return;
70 } 70 }
71 if prev.kind() == T![,] && next.kind() == T!['}'] { 71 if prev.kind() == T![,] && next.kind() == T!['}'] {
@@ -76,7 +76,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
76 " " 76 " "
77 }; 77 };
78 edit.replace( 78 edit.replace(
79 TextRange::from_to(prev.text_range().start(), token.text_range().end()), 79 TextRange::new(prev.text_range().start(), token.text_range().end()),
80 space.to_string(), 80 space.to_string(),
81 ); 81 );
82 return; 82 return;
@@ -87,9 +87,9 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
87 next.as_token().cloned().and_then(ast::Comment::cast), 87 next.as_token().cloned().and_then(ast::Comment::cast),
88 ) { 88 ) {
89 // Removes: newline (incl. surrounding whitespace), start of the next comment 89 // Removes: newline (incl. surrounding whitespace), start of the next comment
90 edit.delete(TextRange::from_to( 90 edit.delete(TextRange::new(
91 token.text_range().start(), 91 token.text_range().start(),
92 next.syntax().text_range().start() + TextUnit::of_str(next.prefix()), 92 next.syntax().text_range().start() + TextSize::of(next.prefix()),
93 )); 93 ));
94 return; 94 return;
95 } 95 }
@@ -420,10 +420,10 @@ fn foo() {
420 check_join_lines( 420 check_join_lines(
421 r" 421 r"
422<|>use ra_syntax::{ 422<|>use ra_syntax::{
423 TextUnit, TextRange, 423 TextSize, TextRange,
424};", 424};",
425 r" 425 r"
426<|>use ra_syntax::{TextUnit, TextRange, 426<|>use ra_syntax::{TextSize, TextRange,
427};", 427};",
428 ); 428 );
429 } 429 }
@@ -434,11 +434,11 @@ fn foo() {
434 check_join_lines( 434 check_join_lines(
435 r" 435 r"
436use ra_syntax::{ 436use ra_syntax::{
437<|> TextUnit, TextRange 437<|> TextSize, TextRange
438};", 438};",
439 r" 439 r"
440use ra_syntax::{ 440use ra_syntax::{
441<|> TextUnit, TextRange};", 441<|> TextSize, TextRange};",
442 ); 442 );
443 } 443 }
444 444
@@ -448,11 +448,11 @@ use ra_syntax::{
448 check_join_lines( 448 check_join_lines(
449 r" 449 r"
450use ra_syntax::{ 450use ra_syntax::{
451<|> TextUnit, TextRange, 451<|> TextSize, TextRange,
452};", 452};",
453 r" 453 r"
454use ra_syntax::{ 454use ra_syntax::{
455<|> TextUnit, TextRange};", 455<|> TextSize, TextRange};",
456 ); 456 );
457 } 457 }
458 458
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index f692fbaa2..09f602fe1 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -60,7 +60,7 @@ use ra_ide_db::{
60 symbol_index::{self, FileSymbol}, 60 symbol_index::{self, FileSymbol},
61 LineIndexDatabase, 61 LineIndexDatabase,
62}; 62};
63use ra_syntax::{SourceFile, TextRange, TextUnit}; 63use ra_syntax::{SourceFile, TextRange, TextSize};
64 64
65use crate::display::ToNav; 65use crate::display::ToNav;
66 66
@@ -265,7 +265,7 @@ impl Analysis {
265 265
266 /// Returns position of the matching brace (all types of braces are 266 /// Returns position of the matching brace (all types of braces are
267 /// supported). 267 /// supported).
268 pub fn matching_brace(&self, position: FilePosition) -> Cancelable<Option<TextUnit>> { 268 pub fn matching_brace(&self, position: FilePosition) -> Cancelable<Option<TextSize>> {
269 self.with_db(|db| { 269 self.with_db(|db| {
270 let parse = db.parse(position.file_id); 270 let parse = db.parse(position.file_id);
271 let file = parse.tree(); 271 let file = parse.tree();
diff --git a/crates/ra_ide/src/matching_brace.rs b/crates/ra_ide/src/matching_brace.rs
index d1204fac0..b85348706 100644
--- a/crates/ra_ide/src/matching_brace.rs
+++ b/crates/ra_ide/src/matching_brace.rs
@@ -1,8 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ast::AstNode, SourceFile, SyntaxKind, TextUnit, T}; 3use ra_syntax::{ast::AstNode, SourceFile, SyntaxKind, TextSize, T};
4 4
5pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> { 5pub fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
6 const BRACES: &[SyntaxKind] = 6 const BRACES: &[SyntaxKind] =
7 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>]]; 7 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>]];
8 let (brace_node, brace_idx) = file 8 let (brace_node, brace_idx) = file
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 9acc6158a..1c64b3eb9 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -54,7 +54,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
54 ReferenceKind::StructFieldShorthandForField => { 54 ReferenceKind::StructFieldShorthandForField => {
55 replacement_text.push_str(new_name); 55 replacement_text.push_str(new_name);
56 replacement_text.push_str(": "); 56 replacement_text.push_str(": ");
57 TextRange::from_to( 57 TextRange::new(
58 reference.file_range.range.start(), 58 reference.file_range.range.start(),
59 reference.file_range.range.start(), 59 reference.file_range.range.start(),
60 ) 60 )
@@ -62,7 +62,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
62 ReferenceKind::StructFieldShorthandForLocal => { 62 ReferenceKind::StructFieldShorthandForLocal => {
63 replacement_text.push_str(": "); 63 replacement_text.push_str(": ");
64 replacement_text.push_str(new_name); 64 replacement_text.push_str(new_name);
65 TextRange::from_to(reference.file_range.range.end(), reference.file_range.range.end()) 65 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end())
66 } 66 }
67 _ => { 67 _ => {
68 replacement_text.push_str(new_name); 68 replacement_text.push_str(new_name);
diff --git a/crates/ra_ide/src/source_change.rs b/crates/ra_ide/src/source_change.rs
index f5f7f8807..71b0e8f75 100644
--- a/crates/ra_ide/src/source_change.rs
+++ b/crates/ra_ide/src/source_change.rs
@@ -6,7 +6,7 @@
6use ra_db::RelativePathBuf; 6use ra_db::RelativePathBuf;
7use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
8 8
9use crate::{FileId, FilePosition, SourceRootId, TextUnit}; 9use crate::{FileId, FilePosition, SourceRootId, TextSize};
10 10
11#[derive(Debug)] 11#[derive(Debug)]
12pub struct SourceChange { 12pub struct SourceChange {
@@ -104,7 +104,7 @@ pub enum FileSystemEdit {
104pub(crate) struct SingleFileChange { 104pub(crate) struct SingleFileChange {
105 pub label: String, 105 pub label: String,
106 pub edit: TextEdit, 106 pub edit: TextEdit,
107 pub cursor_position: Option<TextUnit>, 107 pub cursor_position: Option<TextSize>,
108} 108}
109 109
110impl SingleFileChange { 110impl SingleFileChange {
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index c0728bfb1..6f02614a6 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -61,16 +61,16 @@ impl HighlightedRangeStack {
61 let prev = self.stack.last_mut().unwrap(); 61 let prev = self.stack.last_mut().unwrap();
62 let needs_flattening = !children.is_empty() 62 let needs_flattening = !children.is_empty()
63 && !prev.is_empty() 63 && !prev.is_empty()
64 && children.first().unwrap().range.is_subrange(&prev.last().unwrap().range); 64 && prev.last().unwrap().range.contains_range(children.first().unwrap().range);
65 if !needs_flattening { 65 if !needs_flattening {
66 prev.extend(children); 66 prev.extend(children);
67 } else { 67 } else {
68 let mut parent = prev.pop().unwrap(); 68 let mut parent = prev.pop().unwrap();
69 for ele in children { 69 for ele in children {
70 assert!(ele.range.is_subrange(&parent.range)); 70 assert!(parent.range.contains_range(ele.range));
71 let mut cloned = parent.clone(); 71 let mut cloned = parent.clone();
72 parent.range = TextRange::from_to(parent.range.start(), ele.range.start()); 72 parent.range = TextRange::new(parent.range.start(), ele.range.start());
73 cloned.range = TextRange::from_to(ele.range.end(), cloned.range.end()); 73 cloned.range = TextRange::new(ele.range.end(), cloned.range.end());
74 if !parent.range.is_empty() { 74 if !parent.range.is_empty() {
75 prev.push(parent); 75 prev.push(parent);
76 } 76 }
@@ -152,7 +152,7 @@ pub(crate) fn highlight(
152 }; 152 };
153 153
154 // Element outside of the viewport, no need to highlight 154 // Element outside of the viewport, no need to highlight
155 if range_to_highlight.intersection(&event_range).is_none() { 155 if range_to_highlight.intersect(event_range).is_none() {
156 continue; 156 continue;
157 } 157 }
158 158
@@ -309,7 +309,7 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
309 } 309 }
310 } 310 }
311 311
312 Some(TextRange::from_to(range_start, range_end)) 312 Some(TextRange::new(range_start, range_end))
313} 313}
314 314
315fn highlight_element( 315fn highlight_element(
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 4496529a1..4f17d1040 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -1,7 +1,7 @@
1//! Renders a bit of code as HTML. 1//! Renders a bit of code as HTML.
2 2
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_syntax::{AstNode, TextUnit}; 4use ra_syntax::{AstNode, TextSize};
5 5
6use crate::{FileId, RootDatabase}; 6use crate::{FileId, RootDatabase};
7 7
@@ -23,17 +23,18 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
23 23
24 let ranges = highlight(db, file_id, None); 24 let ranges = highlight(db, file_id, None);
25 let text = parse.tree().syntax().to_string(); 25 let text = parse.tree().syntax().to_string();
26 let mut prev_pos = TextUnit::from(0); 26 let mut prev_pos = TextSize::from(0);
27 let mut buf = String::new(); 27 let mut buf = String::new();
28 buf.push_str(&STYLE); 28 buf.push_str(&STYLE);
29 buf.push_str("<pre><code>"); 29 buf.push_str("<pre><code>");
30 // TODO: unusize
30 for range in &ranges { 31 for range in &ranges {
31 if range.range.start() > prev_pos { 32 if range.range.start() > prev_pos {
32 let curr = &text[prev_pos.to_usize()..range.range.start().to_usize()]; 33 let curr = &text[usize::from(prev_pos)..usize::from(range.range.start())];
33 let text = html_escape(curr); 34 let text = html_escape(curr);
34 buf.push_str(&text); 35 buf.push_str(&text);
35 } 36 }
36 let curr = &text[range.range.start().to_usize()..range.range.end().to_usize()]; 37 let curr = &text[usize::from(range.range.start())..usize::from(range.range.end())];
37 38
38 let class = range.highlight.to_string().replace('.', " "); 39 let class = range.highlight.to_string().replace('.', " ");
39 let color = match (rainbow, range.binding_hash) { 40 let color = match (rainbow, range.binding_hash) {
@@ -47,7 +48,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
47 prev_pos = range.range.end(); 48 prev_pos = range.range.end();
48 } 49 }
49 // Add the remaining (non-highlighted) text 50 // Add the remaining (non-highlighted) text
50 let curr = &text[prev_pos.to_usize()..]; 51 let curr = &text[usize::from(prev_pos)..];
51 let text = html_escape(curr); 52 let text = html_escape(curr);
52 buf.push_str(&text); 53 buf.push_str(&text);
53 buf.push_str("</code></pre>"); 54 buf.push_str("</code></pre>");
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs
index 5842ae2e8..a8a97a69f 100644
--- a/crates/ra_ide/src/syntax_tree.rs
+++ b/crates/ra_ide/src/syntax_tree.rs
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase;
5use ra_syntax::{ 5use ra_syntax::{
6 algo, AstNode, NodeOrToken, SourceFile, 6 algo, AstNode, NodeOrToken, SourceFile,
7 SyntaxKind::{RAW_STRING, STRING}, 7 SyntaxKind::{RAW_STRING, STRING},
8 SyntaxToken, TextRange, TextUnit, 8 SyntaxToken, TextRange, TextSize,
9}; 9};
10 10
11pub use ra_db::FileId; 11pub use ra_db::FileId;
@@ -66,13 +66,13 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St
66 let len = len.min(node_len); 66 let len = len.min(node_len);
67 67
68 // Ensure our slice is inside the actual string 68 // Ensure our slice is inside the actual string
69 let end = if start + len < TextUnit::of_str(&text) { 69 let end = if start + len < TextSize::of(&text) {
70 start + len 70 start + len
71 } else { 71 } else {
72 TextUnit::of_str(&text) - start 72 TextSize::of(&text) - start
73 }; 73 };
74 74
75 let text = &text[TextRange::from_to(start, end)]; 75 let text = &text[TextRange::new(start, end)];
76 76
77 // Remove possible extra string quotes from the start 77 // Remove possible extra string quotes from the start
78 // and the end of the string 78 // and the end of the string
diff --git a/crates/ra_ide/src/test_utils.rs b/crates/ra_ide/src/test_utils.rs
index 8adb214d4..f14533e14 100644
--- a/crates/ra_ide/src/test_utils.rs
+++ b/crates/ra_ide/src/test_utils.rs
@@ -1,11 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{SourceFile, TextUnit}; 3use ra_syntax::{SourceFile, TextSize};
4use ra_text_edit::TextEdit; 4use ra_text_edit::TextEdit;
5 5
6pub use test_utils::*; 6pub use test_utils::*;
7 7
8pub fn check_action<F: Fn(&SourceFile, TextUnit) -> Option<TextEdit>>( 8pub fn check_action<F: Fn(&SourceFile, TextSize) -> Option<TextEdit>>(
9 before: &str, 9 before: &str,
10 after: &str, 10 after: &str,
11 f: F, 11 f: F,
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs
index f55cd3bf5..98af79dff 100644
--- a/crates/ra_ide/src/typing.rs
+++ b/crates/ra_ide/src/typing.rs
@@ -21,7 +21,7 @@ use ra_ide_db::RootDatabase;
21use ra_syntax::{ 21use ra_syntax::{
22 algo::find_node_at_offset, 22 algo::find_node_at_offset,
23 ast::{self, AstToken}, 23 ast::{self, AstToken},
24 AstNode, SourceFile, TextRange, TextUnit, 24 AstNode, SourceFile, TextRange, TextSize,
25}; 25};
26use ra_text_edit::TextEdit; 26use ra_text_edit::TextEdit;
27 27
@@ -45,7 +45,7 @@ pub(crate) fn on_char_typed(
45 45
46fn on_char_typed_inner( 46fn on_char_typed_inner(
47 file: &SourceFile, 47 file: &SourceFile,
48 offset: TextUnit, 48 offset: TextSize,
49 char_typed: char, 49 char_typed: char,
50) -> Option<SingleFileChange> { 50) -> Option<SingleFileChange> {
51 assert!(TRIGGER_CHARS.contains(char_typed)); 51 assert!(TRIGGER_CHARS.contains(char_typed));
@@ -60,7 +60,7 @@ fn on_char_typed_inner(
60/// Returns an edit which should be applied after `=` was typed. Primarily, 60/// Returns an edit which should be applied after `=` was typed. Primarily,
61/// this works when adding `let =`. 61/// this works when adding `let =`.
62// FIXME: use a snippet completion instead of this hack here. 62// FIXME: use a snippet completion instead of this hack here.
63fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange> { 63fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> {
64 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 64 assert_eq!(file.syntax().text().char_at(offset), Some('='));
65 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 65 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
66 if let_stmt.semicolon_token().is_some() { 66 if let_stmt.semicolon_token().is_some() {
@@ -86,7 +86,7 @@ fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange>
86} 86}
87 87
88/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 88/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
89fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange> { 89fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> {
90 assert_eq!(file.syntax().text().char_at(offset), Some('.')); 90 assert_eq!(file.syntax().text().char_at(offset), Some('.'));
91 let whitespace = 91 let whitespace =
92 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; 92 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;
@@ -96,13 +96,13 @@ fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange>
96 let newline = text.rfind('\n')?; 96 let newline = text.rfind('\n')?;
97 &text[newline + 1..] 97 &text[newline + 1..]
98 }; 98 };
99 let current_indent_len = TextUnit::of_str(current_indent); 99 let current_indent_len = TextSize::of(current_indent);
100 100
101 // Make sure dot is a part of call chain 101 // Make sure dot is a part of call chain
102 let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?; 102 let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?;
103 let prev_indent = leading_indent(field_expr.syntax())?; 103 let prev_indent = leading_indent(field_expr.syntax())?;
104 let target_indent = format!(" {}", prev_indent); 104 let target_indent = format!(" {}", prev_indent);
105 let target_indent_len = TextUnit::of_str(&target_indent); 105 let target_indent_len = TextSize::of(&target_indent);
106 if current_indent_len == target_indent_len { 106 if current_indent_len == target_indent_len {
107 return None; 107 return None;
108 } 108 }
@@ -110,20 +110,20 @@ fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange>
110 Some(SingleFileChange { 110 Some(SingleFileChange {
111 label: "reindent dot".to_string(), 111 label: "reindent dot".to_string(),
112 edit: TextEdit::replace( 112 edit: TextEdit::replace(
113 TextRange::from_to(offset - current_indent_len, offset), 113 TextRange::new(offset - current_indent_len, offset),
114 target_indent, 114 target_indent,
115 ), 115 ),
116 cursor_position: Some( 116 cursor_position: Some(
117 offset + target_indent_len - current_indent_len + TextUnit::of_char('.'), 117 offset + target_indent_len - current_indent_len + TextSize::of('.'),
118 ), 118 ),
119 }) 119 })
120} 120}
121 121
122/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` 122/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
123fn on_arrow_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange> { 123fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> {
124 let file_text = file.syntax().text(); 124 let file_text = file.syntax().text();
125 assert_eq!(file_text.char_at(offset), Some('>')); 125 assert_eq!(file_text.char_at(offset), Some('>'));
126 let after_arrow = offset + TextUnit::of_char('>'); 126 let after_arrow = offset + TextSize::of('>');
127 if file_text.char_at(after_arrow) != Some('{') { 127 if file_text.char_at(after_arrow) != Some('{') {
128 return None; 128 return None;
129 } 129 }
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs
index 6bcf2d72b..30c8c5572 100644
--- a/crates/ra_ide/src/typing/on_enter.rs
+++ b/crates/ra_ide/src/typing/on_enter.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7 ast::{self, AstToken}, 7 ast::{self, AstToken},
8 AstNode, SmolStr, SourceFile, 8 AstNode, SmolStr, SourceFile,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxToken, TextUnit, TokenAtOffset, 10 SyntaxToken, TextSize, TokenAtOffset,
11}; 11};
12use ra_text_edit::TextEdit; 12use ra_text_edit::TextEdit;
13 13
@@ -28,7 +28,7 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour
28 28
29 let prefix = comment.prefix(); 29 let prefix = comment.prefix();
30 let comment_range = comment.syntax().text_range(); 30 let comment_range = comment.syntax().text_range();
31 if position.offset < comment_range.start() + TextUnit::of_str(prefix) { 31 if position.offset < comment_range.start() + TextSize::of(prefix) {
32 return None; 32 return None;
33 } 33 }
34 34
@@ -39,7 +39,7 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour
39 39
40 let indent = node_indent(&file, comment.syntax())?; 40 let indent = node_indent(&file, comment.syntax())?;
41 let inserted = format!("\n{}{} ", indent, prefix); 41 let inserted = format!("\n{}{} ", indent, prefix);
42 let cursor_position = position.offset + TextUnit::of_str(&inserted); 42 let cursor_position = position.offset + TextSize::of(&inserted);
43 let edit = TextEdit::insert(position.offset, inserted); 43 let edit = TextEdit::insert(position.offset, inserted);
44 44
45 Some( 45 Some(
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs
index 8ae745ff2..7794dc9fd 100644
--- a/crates/ra_ide_db/src/line_index.rs
+++ b/crates/ra_ide_db/src/line_index.rs
@@ -1,14 +1,14 @@
1//! `LineIndex` maps flat `TextUnit` offsets into `(Line, Column)` 1//! `LineIndex` maps flat `TextSize` offsets into `(Line, Column)`
2//! representation. 2//! representation.
3use std::iter; 3use std::iter;
4 4// TODO: un TextSize
5use ra_syntax::{TextRange, TextUnit}; 5use ra_syntax::{TextRange, TextSize};
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use superslice::Ext; 7use superslice::Ext;
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct LineIndex { 10pub struct LineIndex {
11 pub(crate) newlines: Vec<TextUnit>, 11 pub(crate) newlines: Vec<TextSize>,
12 pub(crate) utf16_lines: FxHashMap<u32, Vec<Utf16Char>>, 12 pub(crate) utf16_lines: FxHashMap<u32, Vec<Utf16Char>>,
13} 13}
14 14
@@ -22,12 +22,12 @@ pub struct LineCol {
22 22
23#[derive(Clone, Debug, Hash, PartialEq, Eq)] 23#[derive(Clone, Debug, Hash, PartialEq, Eq)]
24pub(crate) struct Utf16Char { 24pub(crate) struct Utf16Char {
25 pub(crate) start: TextUnit, 25 pub(crate) start: TextSize,
26 pub(crate) end: TextUnit, 26 pub(crate) end: TextSize,
27} 27}
28 28
29impl Utf16Char { 29impl Utf16Char {
30 fn len(&self) -> TextUnit { 30 fn len(&self) -> TextSize {
31 self.end - self.start 31 self.end - self.start
32 } 32 }
33} 33}
@@ -42,7 +42,7 @@ impl LineIndex {
42 let mut curr_col = 0.into(); 42 let mut curr_col = 0.into();
43 let mut line = 0; 43 let mut line = 0;
44 for c in text.chars() { 44 for c in text.chars() {
45 curr_row += TextUnit::of_char(c); 45 curr_row += TextSize::of(c);
46 if c == '\n' { 46 if c == '\n' {
47 newlines.push(curr_row); 47 newlines.push(curr_row);
48 48
@@ -58,8 +58,8 @@ impl LineIndex {
58 continue; 58 continue;
59 } 59 }
60 60
61 let char_len = TextUnit::of_char(c); 61 let char_len = TextSize::of(c);
62 if char_len > TextUnit::from_usize(1) { 62 if char_len > TextSize::from_usize(1) {
63 utf16_chars.push(Utf16Char { start: curr_col, end: curr_col + char_len }); 63 utf16_chars.push(Utf16Char { start: curr_col, end: curr_col + char_len });
64 } 64 }
65 65
@@ -74,7 +74,7 @@ impl LineIndex {
74 LineIndex { newlines, utf16_lines } 74 LineIndex { newlines, utf16_lines }
75 } 75 }
76 76
77 pub fn line_col(&self, offset: TextUnit) -> LineCol { 77 pub fn line_col(&self, offset: TextSize) -> LineCol {
78 let line = self.newlines.upper_bound(&offset) - 1; 78 let line = self.newlines.upper_bound(&offset) - 1;
79 let line_start_offset = self.newlines[line]; 79 let line_start_offset = self.newlines[line];
80 let col = offset - line_start_offset; 80 let col = offset - line_start_offset;
@@ -82,7 +82,7 @@ impl LineIndex {
82 LineCol { line: line as u32, col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32 } 82 LineCol { line: line as u32, col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32 }
83 } 83 }
84 84
85 pub fn offset(&self, line_col: LineCol) -> TextUnit { 85 pub fn offset(&self, line_col: LineCol) -> TextSize {
86 //FIXME: return Result 86 //FIXME: return Result
87 let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16); 87 let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16);
88 self.newlines[line_col.line as usize] + col 88 self.newlines[line_col.line as usize] + col
@@ -97,16 +97,16 @@ impl LineIndex {
97 97
98 all.clone() 98 all.clone()
99 .zip(all.skip(1)) 99 .zip(all.skip(1))
100 .map(|(lo, hi)| TextRange::from_to(lo, hi)) 100 .map(|(lo, hi)| TextRange::new(lo, hi))
101 .filter(|it| !it.is_empty()) 101 .filter(|it| !it.is_empty())
102 } 102 }
103 103
104 fn utf8_to_utf16_col(&self, line: u32, col: TextUnit) -> usize { 104 fn utf8_to_utf16_col(&self, line: u32, col: TextSize) -> usize {
105 if let Some(utf16_chars) = self.utf16_lines.get(&line) { 105 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
106 let mut correction = 0; 106 let mut correction = 0;
107 for c in utf16_chars { 107 for c in utf16_chars {
108 if col >= c.end { 108 if col >= c.end {
109 correction += c.len().to_usize() - 1; 109 correction += usize::from(c.len()) - 1;
110 } else { 110 } else {
111 // From here on, all utf16 characters come *after* the character we are mapping, 111 // From here on, all utf16 characters come *after* the character we are mapping,
112 // so we don't need to take them into account 112 // so we don't need to take them into account
@@ -114,18 +114,18 @@ impl LineIndex {
114 } 114 }
115 } 115 }
116 116
117 col.to_usize() - correction 117 usize::from(col) - correction
118 } else { 118 } else {
119 col.to_usize() 119 usize::from(col)
120 } 120 }
121 } 121 }
122 122
123 fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextUnit { 123 fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextSize {
124 let mut col: TextUnit = col.into(); 124 let mut col: TextSize = col.into();
125 if let Some(utf16_chars) = self.utf16_lines.get(&line) { 125 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
126 for c in utf16_chars { 126 for c in utf16_chars {
127 if col >= c.start { 127 if col >= c.start {
128 col += c.len() - TextUnit::from_usize(1); 128 col += c.len() - TextSize::from_usize(1);
129 } else { 129 } else {
130 // From here on, all utf16 characters come *after* the character we are mapping, 130 // From here on, all utf16 characters come *after* the character we are mapping,
131 // so we don't need to take them into account 131 // so we don't need to take them into account
@@ -200,10 +200,10 @@ const C: char = 'メ';
200 assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20); 200 assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
201 201
202 // UTF-16 to UTF-8, no changes 202 // UTF-16 to UTF-8, no changes
203 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from(15)); 203 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
204 204
205 // UTF-16 to UTF-8 205 // UTF-16 to UTF-8
206 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from(21)); 206 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
207 } 207 }
208 208
209 #[test] 209 #[test]
@@ -228,18 +228,18 @@ const C: char = \"メ メ\";
228 assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15); 228 assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
229 229
230 // UTF-16 to UTF-8 230 // UTF-16 to UTF-8
231 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from_usize(15)); 231 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from_usize(15));
232 232
233 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextUnit::from_usize(20)); 233 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from_usize(20));
234 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from_usize(23)); 234 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from_usize(23));
235 235
236 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); 236 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from_usize(15));
237 } 237 }
238 238
239 #[test] 239 #[test]
240 fn test_splitlines() { 240 fn test_splitlines() {
241 fn r(lo: u32, hi: u32) -> TextRange { 241 fn r(lo: u32, hi: u32) -> TextRange {
242 TextRange::from_to(lo.into(), hi.into()) 242 TextRange::new(lo.into(), hi.into())
243 } 243 }
244 244
245 let text = "a\nbb\nccc\n"; 245 let text = "a\nbb\nccc\n";
diff --git a/crates/ra_ide_db/src/line_index_utils.rs b/crates/ra_ide_db/src/line_index_utils.rs
index 2ebbabdc6..f050fe77f 100644
--- a/crates/ra_ide_db/src/line_index_utils.rs
+++ b/crates/ra_ide_db/src/line_index_utils.rs
@@ -1,20 +1,20 @@
1//! Code actions can specify desirable final position of the cursor. 1//! Code actions can specify desirable final position of the cursor.
2//! 2//!
3//! The position is specified as a `TextUnit` in the final file. We need to send 3//! The position is specified as a `TextSize` in the final file. We need to send
4//! it in `(Line, Column)` coordinate though. However, we only have a LineIndex 4//! it in `(Line, Column)` coordinate though. However, we only have a LineIndex
5//! for a file pre-edit! 5//! for a file pre-edit!
6//! 6//!
7//! Code in this module applies this "to (Line, Column) after edit" 7//! Code in this module applies this "to (Line, Column) after edit"
8//! transformation. 8//! transformation.
9 9
10use ra_syntax::{TextRange, TextUnit}; 10use ra_syntax::{TextRange, TextSize};
11use ra_text_edit::{AtomTextEdit, TextEdit}; 11use ra_text_edit::{AtomTextEdit, TextEdit};
12 12
13use crate::line_index::{LineCol, LineIndex, Utf16Char}; 13use crate::line_index::{LineCol, LineIndex, Utf16Char};
14 14
15pub fn translate_offset_with_edit( 15pub fn translate_offset_with_edit(
16 line_index: &LineIndex, 16 line_index: &LineIndex,
17 offset: TextUnit, 17 offset: TextSize,
18 text_edit: &TextEdit, 18 text_edit: &TextEdit,
19) -> LineCol { 19) -> LineCol {
20 let mut state = Edits::from_text_edit(&text_edit); 20 let mut state = Edits::from_text_edit(&text_edit);
@@ -84,7 +84,7 @@ pub fn translate_offset_with_edit(
84 84
85#[derive(Debug, Clone)] 85#[derive(Debug, Clone)]
86enum Step { 86enum Step {
87 Newline(TextUnit), 87 Newline(TextSize),
88 Utf16Char(TextRange), 88 Utf16Char(TextRange),
89} 89}
90 90
@@ -92,7 +92,7 @@ enum Step {
92struct LineIndexStepIter<'a> { 92struct LineIndexStepIter<'a> {
93 line_index: &'a LineIndex, 93 line_index: &'a LineIndex,
94 next_newline_idx: usize, 94 next_newline_idx: usize,
95 utf16_chars: Option<(TextUnit, std::slice::Iter<'a, Utf16Char>)>, 95 utf16_chars: Option<(TextSize, std::slice::Iter<'a, Utf16Char>)>,
96} 96}
97 97
98impl LineIndexStepIter<'_> { 98impl LineIndexStepIter<'_> {
@@ -111,7 +111,7 @@ impl Iterator for LineIndexStepIter<'_> {
111 .as_mut() 111 .as_mut()
112 .and_then(|(newline, x)| { 112 .and_then(|(newline, x)| {
113 let x = x.next()?; 113 let x = x.next()?;
114 Some(Step::Utf16Char(TextRange::from_to(*newline + x.start, *newline + x.end))) 114 Some(Step::Utf16Char(TextRange::new(*newline + x.start, *newline + x.end)))
115 }) 115 })
116 .or_else(|| { 116 .or_else(|| {
117 let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?; 117 let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?;
@@ -129,7 +129,7 @@ impl Iterator for LineIndexStepIter<'_> {
129#[derive(Debug)] 129#[derive(Debug)]
130struct OffsetStepIter<'a> { 130struct OffsetStepIter<'a> {
131 text: &'a str, 131 text: &'a str,
132 offset: TextUnit, 132 offset: TextSize,
133} 133}
134 134
135impl Iterator for OffsetStepIter<'_> { 135impl Iterator for OffsetStepIter<'_> {
@@ -140,15 +140,15 @@ impl Iterator for OffsetStepIter<'_> {
140 .char_indices() 140 .char_indices()
141 .filter_map(|(i, c)| { 141 .filter_map(|(i, c)| {
142 if c == '\n' { 142 if c == '\n' {
143 let next_offset = self.offset + TextUnit::from_usize(i + 1); 143 let next_offset = self.offset + TextSize::from_usize(i + 1);
144 let next = Step::Newline(next_offset); 144 let next = Step::Newline(next_offset);
145 Some((next, next_offset)) 145 Some((next, next_offset))
146 } else { 146 } else {
147 let char_len = TextUnit::of_char(c); 147 let char_len = TextSize::of(c);
148 if char_len > TextUnit::from_usize(1) { 148 if char_len > TextSize::from_usize(1) {
149 let start = self.offset + TextUnit::from_usize(i); 149 let start = self.offset + TextSize::from_usize(i);
150 let end = start + char_len; 150 let end = start + char_len;
151 let next = Step::Utf16Char(TextRange::from_to(start, end)); 151 let next = Step::Utf16Char(TextRange::new(start, end));
152 let next_offset = end; 152 let next_offset = end;
153 Some((next, next_offset)) 153 Some((next, next_offset))
154 } else { 154 } else {
@@ -157,7 +157,7 @@ impl Iterator for OffsetStepIter<'_> {
157 } 157 }
158 }) 158 })
159 .next()?; 159 .next()?;
160 let next_idx = (next_offset - self.offset).to_usize(); 160 let next_idx: usize = (next_offset - self.offset).into();
161 self.text = &self.text[next_idx..]; 161 self.text = &self.text[next_idx..];
162 self.offset = next_offset; 162 self.offset = next_offset;
163 Some(next) 163 Some(next)
@@ -195,7 +195,7 @@ impl<'a> Edits<'a> {
195 match self.edits.split_first() { 195 match self.edits.split_first() {
196 Some((next, rest)) => { 196 Some((next, rest)) => {
197 let delete = self.translate_range(next.delete); 197 let delete = self.translate_range(next.delete);
198 let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64; 198 let diff = next.insert.len() as i64 - usize::from(next.delete.len()) as i64;
199 self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff }); 199 self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff });
200 self.edits = rest; 200 self.edits = rest;
201 } 201 }
@@ -244,15 +244,15 @@ impl<'a> Edits<'a> {
244 } else { 244 } else {
245 let start = self.translate(range.start()); 245 let start = self.translate(range.start());
246 let end = self.translate(range.end()); 246 let end = self.translate(range.end());
247 TextRange::from_to(start, end) 247 TextRange::new(start, end)
248 } 248 }
249 } 249 }
250 250
251 fn translate(&self, x: TextUnit) -> TextUnit { 251 fn translate(&self, x: TextSize) -> TextSize {
252 if self.acc_diff == 0 { 252 if self.acc_diff == 0 {
253 x 253 x
254 } else { 254 } else {
255 TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32) 255 TextSize::from((usize::from(x) as i64 + self.acc_diff) as u32)
256 } 256 }
257 } 257 }
258 258
@@ -271,29 +271,29 @@ impl<'a> Edits<'a> {
271#[derive(Debug)] 271#[derive(Debug)]
272struct RunningLineCol { 272struct RunningLineCol {
273 line: u32, 273 line: u32,
274 last_newline: TextUnit, 274 last_newline: TextSize,
275 col_adjust: TextUnit, 275 col_adjust: TextSize,
276} 276}
277 277
278impl RunningLineCol { 278impl RunningLineCol {
279 fn new() -> RunningLineCol { 279 fn new() -> RunningLineCol {
280 RunningLineCol { line: 0, last_newline: TextUnit::from(0), col_adjust: TextUnit::from(0) } 280 RunningLineCol { line: 0, last_newline: TextSize::from(0), col_adjust: TextSize::from(0) }
281 } 281 }
282 282
283 fn to_line_col(&self, offset: TextUnit) -> LineCol { 283 fn to_line_col(&self, offset: TextSize) -> LineCol {
284 LineCol { 284 LineCol {
285 line: self.line, 285 line: self.line,
286 col_utf16: ((offset - self.last_newline) - self.col_adjust).into(), 286 col_utf16: ((offset - self.last_newline) - self.col_adjust).into(),
287 } 287 }
288 } 288 }
289 289
290 fn add_line(&mut self, newline: TextUnit) { 290 fn add_line(&mut self, newline: TextSize) {
291 self.line += 1; 291 self.line += 1;
292 self.last_newline = newline; 292 self.last_newline = newline;
293 self.col_adjust = TextUnit::from(0); 293 self.col_adjust = TextSize::from(0);
294 } 294 }
295 295
296 fn adjust_col(&mut self, range: TextRange) { 296 fn adjust_col(&mut self, range: TextRange) {
297 self.col_adjust += range.len() - TextUnit::from(1); 297 self.col_adjust += range.len() - TextSize::from(1);
298 } 298 }
299} 299}
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index 1bf014149..c66de4f42 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -10,7 +10,7 @@ use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility};
10use once_cell::unsync::Lazy; 10use once_cell::unsync::Lazy;
11use ra_db::{FileId, FileRange, SourceDatabaseExt}; 11use ra_db::{FileId, FileRange, SourceDatabaseExt};
12use ra_prof::profile; 12use ra_prof::profile;
13use ra_syntax::{ast, match_ast, AstNode, TextRange, TextUnit}; 13use ra_syntax::{ast, match_ast, AstNode, TextRange, TextSize};
14use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
15use test_utils::tested_by; 15use test_utils::tested_by;
16 16
@@ -85,7 +85,7 @@ impl SearchScope {
85 match (r1, r2) { 85 match (r1, r2) {
86 (None, r) | (r, None) => Some(r), 86 (None, r) | (r, None) => Some(r),
87 (Some(r1), Some(r2)) => { 87 (Some(r1), Some(r2)) => {
88 let r = r1.intersection(&r2)?; 88 let r = r1.intersect(r2)?;
89 Some(Some(r)) 89 Some(Some(r))
90 } 90 }
91 } 91 }
@@ -200,14 +200,13 @@ impl Definition {
200 200
201 for (file_id, search_range) in search_scope { 201 for (file_id, search_range) in search_scope {
202 let text = db.file_text(file_id); 202 let text = db.file_text(file_id);
203 let search_range = 203 let search_range = search_range.unwrap_or(TextRange::up_to(TextSize::of(&text)));
204 search_range.unwrap_or(TextRange::offset_len(0.into(), TextUnit::of_str(&text)));
205 204
206 let sema = Semantics::new(db); 205 let sema = Semantics::new(db);
207 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); 206 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
208 207
209 for (idx, _) in text.match_indices(pat) { 208 for (idx, _) in text.match_indices(pat) {
210 let offset = TextUnit::from_usize(idx); 209 let offset = TextSize::from_usize(idx);
211 if !search_range.contains_inclusive(offset) { 210 if !search_range.contains_inclusive(offset) {
212 tested_by!(search_filters_by_range; force); 211 tested_by!(search_filters_by_range; force);
213 continue; 212 continue;
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 2b4390eb2..fa9787266 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 ast::{self, make::tokens::doc_comment}, 5 ast::{self, make::tokens::doc_comment},
6 tokenize, AstToken, Parse, SmolStr, SyntaxKind, 6 tokenize, AstToken, Parse, SmolStr, SyntaxKind,
7 SyntaxKind::*, 7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextUnit, Token as RawToken, T, 8 SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, Token as RawToken, T,
9}; 9};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11use tt::buffer::{Cursor, TokenBuffer}; 11use tt::buffer::{Cursor, TokenBuffer};
@@ -99,11 +99,11 @@ pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> {
99 99
100 let mut conv = RawConvertor { 100 let mut conv = RawConvertor {
101 text, 101 text,
102 offset: TextUnit::default(), 102 offset: TextSize::default(),
103 inner: tokens.iter(), 103 inner: tokens.iter(),
104 id_alloc: TokenIdAlloc { 104 id_alloc: TokenIdAlloc {
105 map: Default::default(), 105 map: Default::default(),
106 global_offset: TextUnit::default(), 106 global_offset: TextSize::default(),
107 next_id: 0, 107 next_id: 0,
108 }, 108 },
109 }; 109 };
@@ -227,7 +227,7 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
227 227
228struct TokenIdAlloc { 228struct TokenIdAlloc {
229 map: TokenMap, 229 map: TokenMap,
230 global_offset: TextUnit, 230 global_offset: TextSize,
231 next_id: u32, 231 next_id: u32,
232} 232}
233 233
@@ -266,7 +266,7 @@ impl TokenIdAlloc {
266/// A Raw Token (straightly from lexer) convertor 266/// A Raw Token (straightly from lexer) convertor
267struct RawConvertor<'a> { 267struct RawConvertor<'a> {
268 text: &'a str, 268 text: &'a str,
269 offset: TextUnit, 269 offset: TextSize,
270 id_alloc: TokenIdAlloc, 270 id_alloc: TokenIdAlloc,
271 inner: std::slice::Iter<'a, RawToken>, 271 inner: std::slice::Iter<'a, RawToken>,
272} 272}
@@ -314,7 +314,7 @@ trait TokenConvertor {
314 } 314 }
315 315
316 result.push(if k.is_punct() { 316 result.push(if k.is_punct() {
317 assert_eq!(range.len().to_usize(), 1); 317 assert_eq!(range.len(), TextSize::of('.'));
318 let delim = match k { 318 let delim = match k {
319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), 319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
320 T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])), 320 T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])),
@@ -381,8 +381,8 @@ trait TokenConvertor {
381 k if k.is_keyword() => make_leaf!(Ident), 381 k if k.is_keyword() => make_leaf!(Ident),
382 k if k.is_literal() => make_leaf!(Literal), 382 k if k.is_literal() => make_leaf!(Literal),
383 LIFETIME => { 383 LIFETIME => {
384 let char_unit = TextUnit::from_usize(1); 384 let char_unit = TextSize::of('\'');
385 let r = TextRange::offset_len(range.start(), char_unit); 385 let r = TextRange::at(range.start(), char_unit);
386 let apostrophe = tt::Leaf::from(tt::Punct { 386 let apostrophe = tt::Leaf::from(tt::Punct {
387 char: '\'', 387 char: '\'',
388 spacing: tt::Spacing::Joint, 388 spacing: tt::Spacing::Joint,
@@ -390,8 +390,7 @@ trait TokenConvertor {
390 }); 390 });
391 result.push(apostrophe.into()); 391 result.push(apostrophe.into());
392 392
393 let r = 393 let r = TextRange::at(range.start() + char_unit, range.len() - char_unit);
394 TextRange::offset_len(range.start() + char_unit, range.len() - char_unit);
395 let ident = tt::Leaf::from(tt::Ident { 394 let ident = tt::Leaf::from(tt::Ident {
396 text: SmolStr::new(&token.to_text()[1..]), 395 text: SmolStr::new(&token.to_text()[1..]),
397 id: self.id_alloc().alloc(r), 396 id: self.id_alloc().alloc(r),
@@ -440,7 +439,7 @@ impl<'a> TokenConvertor for RawConvertor<'a> {
440 439
441 fn bump(&mut self) -> Option<(Self::Token, TextRange)> { 440 fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
442 let token = self.inner.next()?; 441 let token = self.inner.next()?;
443 let range = TextRange::offset_len(self.offset, token.len); 442 let range = TextRange::at(self.offset, token.len);
444 self.offset += token.len; 443 self.offset += token.len;
445 444
446 Some(((*token, &self.text[range]), range)) 445 Some(((*token, &self.text[range]), range))
@@ -450,7 +449,7 @@ impl<'a> TokenConvertor for RawConvertor<'a> {
450 let token = self.inner.as_slice().get(0).cloned(); 449 let token = self.inner.as_slice().get(0).cloned();
451 450
452 token.map(|it| { 451 token.map(|it| {
453 let range = TextRange::offset_len(self.offset, it.len); 452 let range = TextRange::at(self.offset, it.len);
454 (it, &self.text[range]) 453 (it, &self.text[range])
455 }) 454 })
456 } 455 }
@@ -464,11 +463,11 @@ struct Convertor {
464 id_alloc: TokenIdAlloc, 463 id_alloc: TokenIdAlloc,
465 current: Option<SyntaxToken>, 464 current: Option<SyntaxToken>,
466 range: TextRange, 465 range: TextRange,
467 punct_offset: Option<(SyntaxToken, TextUnit)>, 466 punct_offset: Option<(SyntaxToken, TextSize)>,
468} 467}
469 468
470impl Convertor { 469impl Convertor {
471 fn new(node: &SyntaxNode, global_offset: TextUnit) -> Convertor { 470 fn new(node: &SyntaxNode, global_offset: TextSize) -> Convertor {
472 Convertor { 471 Convertor {
473 id_alloc: { TokenIdAlloc { map: TokenMap::default(), global_offset, next_id: 0 } }, 472 id_alloc: { TokenIdAlloc { map: TokenMap::default(), global_offset, next_id: 0 } },
474 current: node.first_token(), 473 current: node.first_token(),
@@ -481,7 +480,7 @@ impl Convertor {
481#[derive(Debug)] 480#[derive(Debug)]
482enum SynToken { 481enum SynToken {
483 Ordiniary(SyntaxToken), 482 Ordiniary(SyntaxToken),
484 Punch(SyntaxToken, TextUnit), 483 Punch(SyntaxToken, TextSize),
485} 484}
486 485
487impl SynToken { 486impl SynToken {
@@ -500,7 +499,7 @@ impl SrcToken for SynToken {
500 fn to_char(&self) -> Option<char> { 499 fn to_char(&self) -> Option<char> {
501 match self { 500 match self {
502 SynToken::Ordiniary(_) => None, 501 SynToken::Ordiniary(_) => None,
503 SynToken::Punch(it, i) => it.text().chars().nth(i.to_usize()), 502 SynToken::Punch(it, i) => it.text().chars().nth((*i).into()),
504 } 503 }
505 } 504 }
506 fn to_text(&self) -> SmolStr { 505 fn to_text(&self) -> SmolStr {
@@ -516,26 +515,26 @@ impl TokenConvertor for Convertor {
516 515
517 fn bump(&mut self) -> Option<(Self::Token, TextRange)> { 516 fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
518 if let Some((punct, offset)) = self.punct_offset.clone() { 517 if let Some((punct, offset)) = self.punct_offset.clone() {
519 if offset.to_usize() + 1 < punct.text().len() { 518 if usize::from(offset) + 1 < punct.text().len() {
520 let offset = offset + TextUnit::from_usize(1); 519 let offset = offset + TextSize::from_usize(1);
521 let range = punct.text_range(); 520 let range = punct.text_range();
522 self.punct_offset = Some((punct.clone(), offset)); 521 self.punct_offset = Some((punct.clone(), offset));
523 let range = TextRange::offset_len(range.start() + offset, TextUnit::from_usize(1)); 522 let range = TextRange::at(range.start() + offset, TextSize::of('.'));
524 return Some((SynToken::Punch(punct, offset), range)); 523 return Some((SynToken::Punch(punct, offset), range));
525 } 524 }
526 } 525 }
527 526
528 let curr = self.current.clone()?; 527 let curr = self.current.clone()?;
529 if !curr.text_range().is_subrange(&self.range) { 528 if !&self.range.contains_range(curr.text_range()) {
530 return None; 529 return None;
531 } 530 }
532 self.current = curr.next_token(); 531 self.current = curr.next_token();
533 532
534 let token = if curr.kind().is_punct() { 533 let token = if curr.kind().is_punct() {
535 let range = curr.text_range(); 534 let range = curr.text_range();
536 let range = TextRange::offset_len(range.start(), TextUnit::from_usize(1)); 535 let range = TextRange::at(range.start(), TextSize::from_usize(1));
537 self.punct_offset = Some((curr.clone(), TextUnit::from_usize(0))); 536 self.punct_offset = Some((curr.clone(), TextSize::from_usize(0)));
538 (SynToken::Punch(curr, TextUnit::from_usize(0)), range) 537 (SynToken::Punch(curr, TextSize::from_usize(0)), range)
539 } else { 538 } else {
540 self.punct_offset = None; 539 self.punct_offset = None;
541 let range = curr.text_range(); 540 let range = curr.text_range();
@@ -547,19 +546,19 @@ impl TokenConvertor for Convertor {
547 546
548 fn peek(&self) -> Option<Self::Token> { 547 fn peek(&self) -> Option<Self::Token> {
549 if let Some((punct, mut offset)) = self.punct_offset.clone() { 548 if let Some((punct, mut offset)) = self.punct_offset.clone() {
550 offset = offset + TextUnit::from_usize(1); 549 offset = offset + TextSize::from_usize(1);
551 if offset.to_usize() < punct.text().len() { 550 if usize::from(offset) < punct.text().len() {
552 return Some(SynToken::Punch(punct, offset)); 551 return Some(SynToken::Punch(punct, offset));
553 } 552 }
554 } 553 }
555 554
556 let curr = self.current.clone()?; 555 let curr = self.current.clone()?;
557 if !curr.text_range().is_subrange(&self.range) { 556 if !self.range.contains_range(curr.text_range()) {
558 return None; 557 return None;
559 } 558 }
560 559
561 let token = if curr.kind().is_punct() { 560 let token = if curr.kind().is_punct() {
562 SynToken::Punch(curr, TextUnit::from_usize(0)) 561 SynToken::Punch(curr, TextSize::from_usize(0))
563 } else { 562 } else {
564 SynToken::Ordiniary(curr) 563 SynToken::Ordiniary(curr)
565 }; 564 };
@@ -574,8 +573,8 @@ impl TokenConvertor for Convertor {
574struct TtTreeSink<'a> { 573struct TtTreeSink<'a> {
575 buf: String, 574 buf: String,
576 cursor: Cursor<'a>, 575 cursor: Cursor<'a>,
577 open_delims: FxHashMap<tt::TokenId, TextUnit>, 576 open_delims: FxHashMap<tt::TokenId, TextSize>,
578 text_pos: TextUnit, 577 text_pos: TextSize,
579 inner: SyntaxTreeBuilder, 578 inner: SyntaxTreeBuilder,
580 token_map: TokenMap, 579 token_map: TokenMap,
581 580
@@ -641,7 +640,7 @@ impl<'a> TreeSink for TtTreeSink<'a> {
641 } 640 }
642 tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id), 641 tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id),
643 }; 642 };
644 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text)); 643 let range = TextRange::at(self.text_pos, TextSize::of(text.as_str()));
645 self.token_map.insert(id, range); 644 self.token_map.insert(id, range);
646 self.cursor = self.cursor.bump(); 645 self.cursor = self.cursor.bump();
647 text 646 text
@@ -658,10 +657,8 @@ impl<'a> TreeSink for TtTreeSink<'a> {
658 self.cursor = self.cursor.bump(); 657 self.cursor = self.cursor.bump();
659 if let Some(id) = parent.delimiter.map(|it| it.id) { 658 if let Some(id) = parent.delimiter.map(|it| it.id) {
660 if let Some(open_delim) = self.open_delims.get(&id) { 659 if let Some(open_delim) = self.open_delims.get(&id) {
661 let open_range = 660 let open_range = TextRange::at(*open_delim, TextSize::of('('));
662 TextRange::offset_len(*open_delim, TextUnit::from_usize(1)); 661 let close_range = TextRange::at(self.text_pos, TextSize::of('('));
663 let close_range =
664 TextRange::offset_len(self.text_pos, TextUnit::from_usize(1));
665 self.token_map.insert_delim(id, open_range, close_range); 662 self.token_map.insert_delim(id, open_range, close_range);
666 } 663 }
667 } 664 }
@@ -672,7 +669,7 @@ impl<'a> TreeSink for TtTreeSink<'a> {
672 } 669 }
673 }; 670 };
674 self.buf += &text; 671 self.buf += &text;
675 self.text_pos += TextUnit::of_str(&text); 672 self.text_pos += TextSize::of(text.as_str());
676 } 673 }
677 674
678 let text = SmolStr::new(self.buf.as_str()); 675 let text = SmolStr::new(self.buf.as_str());
@@ -690,7 +687,7 @@ impl<'a> TreeSink for TtTreeSink<'a> {
690 // other parts of RA such that we don't add whitespace here. 687 // other parts of RA such that we don't add whitespace here.
691 if curr.spacing == tt::Spacing::Alone && curr.char != ';' { 688 if curr.spacing == tt::Spacing::Alone && curr.char != ';' {
692 self.inner.token(WHITESPACE, " ".into()); 689 self.inner.token(WHITESPACE, " ".into());
693 self.text_pos += TextUnit::of_char(' '); 690 self.text_pos += TextSize::of(' ');
694 } 691 }
695 } 692 }
696 } 693 }
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 75a2f696e..dda396582 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
12 12
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.9.1" 15rowan = { path = "../../../rowan" }
16rustc_lexer = { version = "652.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "652.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 06df8495c..2a8dac757 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
11 11
12use crate::{ 12use crate::{
13 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, 13 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
14 SyntaxToken, TextRange, TextUnit, 14 SyntaxToken, TextRange, TextSize,
15}; 15};
16 16
17/// Returns ancestors of the node at the offset, sorted by length. This should 17/// Returns ancestors of the node at the offset, sorted by length. This should
@@ -21,7 +21,7 @@ use crate::{
21/// t.parent().ancestors())`. 21/// t.parent().ancestors())`.
22pub fn ancestors_at_offset( 22pub fn ancestors_at_offset(
23 node: &SyntaxNode, 23 node: &SyntaxNode,
24 offset: TextUnit, 24 offset: TextSize,
25) -> impl Iterator<Item = SyntaxNode> { 25) -> impl Iterator<Item = SyntaxNode> {
26 node.token_at_offset(offset) 26 node.token_at_offset(offset)
27 .map(|token| token.parent().ancestors()) 27 .map(|token| token.parent().ancestors())
@@ -37,7 +37,7 @@ pub fn ancestors_at_offset(
37/// ``` 37/// ```
38/// 38///
39/// then the shorter node will be silently preferred. 39/// then the shorter node will be silently preferred.
40pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<N> { 40pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextSize) -> Option<N> {
41 ancestors_at_offset(syntax, offset).find_map(N::cast) 41 ancestors_at_offset(syntax, offset).find_map(N::cast)
42} 42}
43 43
@@ -180,7 +180,7 @@ fn _insert_children(
180 position: InsertPosition<SyntaxElement>, 180 position: InsertPosition<SyntaxElement>,
181 to_insert: &mut dyn Iterator<Item = SyntaxElement>, 181 to_insert: &mut dyn Iterator<Item = SyntaxElement>,
182) -> SyntaxNode { 182) -> SyntaxNode {
183 let mut delta = TextUnit::default(); 183 let mut delta = TextSize::default();
184 let to_insert = to_insert.map(|element| { 184 let to_insert = to_insert.map(|element| {
185 delta += element.text_range().len(); 185 delta += element.text_range().len();
186 to_green_element(element) 186 to_green_element(element)
@@ -347,7 +347,7 @@ fn with_children(
347 parent: &SyntaxNode, 347 parent: &SyntaxNode,
348 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, 348 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
349) -> SyntaxNode { 349) -> SyntaxNode {
350 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>(); 350 let len = new_children.iter().map(|it| it.text_len()).sum::<TextSize>();
351 let new_node = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children); 351 let new_node = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children);
352 let new_root_node = parent.replace_with(new_node); 352 let new_root_node = parent.replace_with(new_node);
353 let new_root_node = SyntaxNode::new_root(new_root_node); 353 let new_root_node = SyntaxNode::new_root(new_root_node);
@@ -355,7 +355,7 @@ fn with_children(
355 // FIXME: use a more elegant way to re-fetch the node (#1185), make 355 // FIXME: use a more elegant way to re-fetch the node (#1185), make
356 // `range` private afterwards 356 // `range` private afterwards
357 let mut ptr = SyntaxNodePtr::new(parent); 357 let mut ptr = SyntaxNodePtr::new(parent);
358 ptr.range = TextRange::offset_len(ptr.range.start(), len); 358 ptr.range = TextRange::at(ptr.range.start(), len);
359 ptr.to_node(&new_root_node) 359 ptr.to_node(&new_root_node)
360} 360}
361 361
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index aa34b682d..26b8f9c36 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -2,7 +2,7 @@
2 2
3use crate::{ 3use crate::{
4 ast::{AstToken, Comment, RawString, String, Whitespace}, 4 ast::{AstToken, Comment, RawString, String, Whitespace},
5 TextRange, TextUnit, 5 TextRange, TextSize,
6}; 6};
7 7
8impl Comment { 8impl Comment {
@@ -94,14 +94,14 @@ impl QuoteOffsets {
94 return None; 94 return None;
95 } 95 }
96 96
97 let start = TextUnit::from(0); 97 let start = TextSize::from(0);
98 let left_quote = TextUnit::from_usize(left_quote) + TextUnit::of_char('"'); 98 let left_quote = TextSize::from_usize(left_quote) + TextSize::of('"');
99 let right_quote = TextUnit::from_usize(right_quote); 99 let right_quote = TextSize::from_usize(right_quote);
100 let end = TextUnit::of_str(literal); 100 let end = TextSize::of(literal);
101 101
102 let res = QuoteOffsets { 102 let res = QuoteOffsets {
103 quotes: [TextRange::from_to(start, left_quote), TextRange::from_to(right_quote, end)], 103 quotes: [TextRange::new(start, left_quote), TextRange::new(right_quote, end)],
104 contents: TextRange::from_to(left_quote, right_quote), 104 contents: TextRange::new(left_quote, right_quote),
105 }; 105 };
106 Some(res) 106 Some(res)
107 } 107 }
@@ -168,7 +168,7 @@ impl HasStringValue for RawString {
168impl RawString { 168impl RawString {
169 pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> { 169 pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> {
170 let contents_range = self.text_range_between_quotes()?; 170 let contents_range = self.text_range_between_quotes()?;
171 assert!(range.is_subrange(&TextRange::offset_len(0.into(), contents_range.len()))); 171 assert!(TextRange::up_to(contents_range.len()).contains_range(range));
172 Some(range + contents_range.start()) 172 Some(range + contents_range.start())
173 } 173 }
174} 174}
@@ -459,7 +459,7 @@ pub trait HasFormatSpecifier: AstToken {
459 while let Some((r, Ok(next_char))) = chars.peek() { 459 while let Some((r, Ok(next_char))) = chars.peek() {
460 if next_char.is_ascii_digit() { 460 if next_char.is_ascii_digit() {
461 chars.next(); 461 chars.next();
462 range = range.extend_to(r); 462 range = range.cover(*r);
463 } else { 463 } else {
464 break; 464 break;
465 } 465 }
@@ -477,7 +477,7 @@ pub trait HasFormatSpecifier: AstToken {
477 while let Some((r, Ok(next_char))) = chars.peek() { 477 while let Some((r, Ok(next_char))) = chars.peek() {
478 if *next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() { 478 if *next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
479 chars.next(); 479 chars.next();
480 range = range.extend_to(r); 480 range = range.cover(*r);
481 } else { 481 } else {
482 break; 482 break;
483 } 483 }
@@ -498,10 +498,8 @@ impl HasFormatSpecifier for String {
498 let mut res = Vec::with_capacity(text.len()); 498 let mut res = Vec::with_capacity(text.len());
499 rustc_lexer::unescape::unescape_str(text, &mut |range, unescaped_char| { 499 rustc_lexer::unescape::unescape_str(text, &mut |range, unescaped_char| {
500 res.push(( 500 res.push((
501 TextRange::from_to( 501 TextRange::new(TextSize::from_usize(range.start), TextSize::from_usize(range.end))
502 TextUnit::from_usize(range.start), 502 + offset,
503 TextUnit::from_usize(range.end),
504 ) + offset,
505 unescaped_char, 503 unescaped_char,
506 )) 504 ))
507 }); 505 });
@@ -521,10 +519,8 @@ impl HasFormatSpecifier for RawString {
521 let mut res = Vec::with_capacity(text.len()); 519 let mut res = Vec::with_capacity(text.len());
522 for (idx, c) in text.char_indices() { 520 for (idx, c) in text.char_indices() {
523 res.push(( 521 res.push((
524 TextRange::from_to( 522 TextRange::new(TextSize::from_usize(idx), TextSize::from_usize(idx + c.len_utf8()))
525 TextUnit::from_usize(idx), 523 + offset,
526 TextUnit::from_usize(idx + c.len_utf8()),
527 ) + offset,
528 Ok(c), 524 Ok(c),
529 )); 525 ));
530 } 526 }
diff --git a/crates/ra_syntax/src/fuzz.rs b/crates/ra_syntax/src/fuzz.rs
index 7012df7f0..15aad2205 100644
--- a/crates/ra_syntax/src/fuzz.rs
+++ b/crates/ra_syntax/src/fuzz.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{validation, AstNode, SourceFile, TextRange, TextUnit}; 3use crate::{validation, AstNode, SourceFile, TextRange, TextSize};
4use ra_text_edit::AtomTextEdit; 4use ra_text_edit::AtomTextEdit;
5use std::str::{self, FromStr}; 5use std::str::{self, FromStr};
6 6
@@ -34,10 +34,8 @@ impl CheckReparse {
34 let text = lines.collect::<Vec<_>>().join("\n"); 34 let text = lines.collect::<Vec<_>>().join("\n");
35 let text = format!("{}{}{}", PREFIX, text, SUFFIX); 35 let text = format!("{}{}{}", PREFIX, text, SUFFIX);
36 text.get(delete_start..delete_start.checked_add(delete_len)?)?; // make sure delete is a valid range 36 text.get(delete_start..delete_start.checked_add(delete_len)?)?; // make sure delete is a valid range
37 let delete = TextRange::offset_len( 37 let delete =
38 TextUnit::from_usize(delete_start), 38 TextRange::at(TextSize::from_usize(delete_start), TextSize::from_usize(delete_len));
39 TextUnit::from_usize(delete_len),
40 );
41 let edited_text = 39 let edited_text =
42 format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); 40 format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
43 let edit = AtomTextEdit { delete, insert }; 41 let edit = AtomTextEdit { delete, insert };
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index a796e78b1..ceeb2bde9 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -55,7 +55,7 @@ pub use crate::{
55 }, 55 },
56}; 56};
57pub use ra_parser::{SyntaxKind, T}; 57pub use ra_parser::{SyntaxKind, T};
58pub use rowan::{SmolStr, SyntaxText, TextRange, TextUnit, TokenAtOffset, WalkEvent}; 58pub use rowan::{SmolStr, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent};
59 59
60/// `Parse` is the result of the parsing: a syntax tree and a collection of 60/// `Parse` is the result of the parsing: a syntax tree and a collection of
61/// errors. 61/// errors.
@@ -266,7 +266,7 @@ fn api_walkthrough() {
266 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR); 266 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
267 267
268 // And text range: 268 // And text range:
269 assert_eq!(expr_syntax.text_range(), TextRange::from_to(32.into(), 37.into())); 269 assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
270 270
271 // You can get node's text as a `SyntaxText` object, which will traverse the 271 // You can get node's text as a `SyntaxText` object, which will traverse the
272 // tree collecting token's text: 272 // tree collecting token's text:
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs
index 67c1f1b48..1fdc76d98 100644
--- a/crates/ra_syntax/src/parsing/lexer.rs
+++ b/crates/ra_syntax/src/parsing/lexer.rs
@@ -4,7 +4,7 @@
4use crate::{ 4use crate::{
5 SyntaxError, 5 SyntaxError,
6 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
7 TextRange, TextUnit, T, 7 TextRange, TextSize, T,
8}; 8};
9 9
10/// A token of Rust source. 10/// A token of Rust source.
@@ -13,7 +13,7 @@ pub struct Token {
13 /// The kind of token. 13 /// The kind of token.
14 pub kind: SyntaxKind, 14 pub kind: SyntaxKind,
15 /// The length of the token. 15 /// The length of the token.
16 pub len: TextUnit, 16 pub len: TextSize,
17} 17}
18 18
19/// Break a string up into its component tokens. 19/// Break a string up into its component tokens.
@@ -30,7 +30,7 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
30 30
31 let mut offset: usize = rustc_lexer::strip_shebang(text) 31 let mut offset: usize = rustc_lexer::strip_shebang(text)
32 .map(|shebang_len| { 32 .map(|shebang_len| {
33 tokens.push(Token { kind: SHEBANG, len: TextUnit::from_usize(shebang_len) }); 33 tokens.push(Token { kind: SHEBANG, len: TextSize::from_usize(shebang_len) });
34 shebang_len 34 shebang_len
35 }) 35 })
36 .unwrap_or(0); 36 .unwrap_or(0);
@@ -38,8 +38,8 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
38 let text_without_shebang = &text[offset..]; 38 let text_without_shebang = &text[offset..];
39 39
40 for rustc_token in rustc_lexer::tokenize(text_without_shebang) { 40 for rustc_token in rustc_lexer::tokenize(text_without_shebang) {
41 let token_len = TextUnit::from_usize(rustc_token.len); 41 let token_len = TextSize::from_usize(rustc_token.len);
42 let token_range = TextRange::offset_len(TextUnit::from_usize(offset), token_len); 42 let token_range = TextRange::at(TextSize::from_usize(offset), token_len);
43 43
44 let (syntax_kind, err_message) = 44 let (syntax_kind, err_message) =
45 rustc_token_kind_to_syntax_kind(&rustc_token.kind, &text[token_range]); 45 rustc_token_kind_to_syntax_kind(&rustc_token.kind, &text[token_range]);
@@ -65,7 +65,7 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
65/// Beware that unescape errors are not checked at tokenization time. 65/// Beware that unescape errors are not checked at tokenization time.
66pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { 66pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> {
67 lex_first_token(text) 67 lex_first_token(text)
68 .filter(|(token, _)| token.len == TextUnit::of_str(text)) 68 .filter(|(token, _)| token.len == TextSize::of(text))
69 .map(|(token, error)| (token.kind, error)) 69 .map(|(token, error)| (token.kind, error))
70} 70}
71 71
@@ -75,7 +75,7 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr
75/// Beware that unescape errors are not checked at tokenization time. 75/// Beware that unescape errors are not checked at tokenization time.
76pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { 76pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> {
77 lex_first_token(text) 77 lex_first_token(text)
78 .filter(|(token, error)| !error.is_some() && token.len == TextUnit::of_str(text)) 78 .filter(|(token, error)| !error.is_some() && token.len == TextSize::of(text))
79 .map(|(token, _error)| token.kind) 79 .map(|(token, _error)| token.kind)
80} 80}
81 81
@@ -96,9 +96,9 @@ fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> {
96 let rustc_token = rustc_lexer::first_token(text); 96 let rustc_token = rustc_lexer::first_token(text);
97 let (syntax_kind, err_message) = rustc_token_kind_to_syntax_kind(&rustc_token.kind, text); 97 let (syntax_kind, err_message) = rustc_token_kind_to_syntax_kind(&rustc_token.kind, text);
98 98
99 let token = Token { kind: syntax_kind, len: TextUnit::from_usize(rustc_token.len) }; 99 let token = Token { kind: syntax_kind, len: TextSize::from_usize(rustc_token.len) };
100 let optional_error = err_message.map(|err_message| { 100 let optional_error = err_message.map(|err_message| {
101 SyntaxError::new(err_message, TextRange::from_to(0.into(), TextUnit::of_str(text))) 101 SyntaxError::new(err_message, TextRange::new(0.into(), TextSize::of(text)))
102 }); 102 });
103 103
104 Some((token, optional_error)) 104 Some((token, optional_error))
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index 2d65b91f1..ffff0a7b2 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -19,7 +19,7 @@ use crate::{
19 syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode}, 19 syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
20 SyntaxError, 20 SyntaxError,
21 SyntaxKind::*, 21 SyntaxKind::*,
22 TextRange, TextUnit, T, 22 TextRange, TextSize, T,
23}; 23};
24 24
25pub(crate) fn incremental_reparse( 25pub(crate) fn incremental_reparse(
@@ -176,7 +176,7 @@ fn merge_errors(
176 if old_err_range.end() <= range_before_reparse.start() { 176 if old_err_range.end() <= range_before_reparse.start() {
177 res.push(old_err); 177 res.push(old_err);
178 } else if old_err_range.start() >= range_before_reparse.end() { 178 } else if old_err_range.start() >= range_before_reparse.end() {
179 let inserted_len = TextUnit::of_str(&edit.insert); 179 let inserted_len = TextSize::of(&edit.insert);
180 res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len())); 180 res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
181 // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug) 181 // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
182 } 182 }
diff --git a/crates/ra_syntax/src/parsing/text_token_source.rs b/crates/ra_syntax/src/parsing/text_token_source.rs
index e2433913c..7ddc2c2c3 100644
--- a/crates/ra_syntax/src/parsing/text_token_source.rs
+++ b/crates/ra_syntax/src/parsing/text_token_source.rs
@@ -3,7 +3,7 @@
3use ra_parser::Token as PToken; 3use ra_parser::Token as PToken;
4use ra_parser::TokenSource; 4use ra_parser::TokenSource;
5 5
6use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextUnit}; 6use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize};
7 7
8pub(crate) struct TextTokenSource<'t> { 8pub(crate) struct TextTokenSource<'t> {
9 text: &'t str, 9 text: &'t str,
@@ -15,7 +15,7 @@ pub(crate) struct TextTokenSource<'t> {
15 /// 0 7 10 15 /// 0 7 10
16 /// ``` 16 /// ```
17 /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]` 17 /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]`
18 start_offsets: Vec<TextUnit>, 18 start_offsets: Vec<TextSize>,
19 /// non-whitespace/comment tokens 19 /// non-whitespace/comment tokens
20 /// ```non-rust 20 /// ```non-rust
21 /// struct Foo {} 21 /// struct Foo {}
@@ -51,12 +51,12 @@ impl<'t> TokenSource for TextTokenSource<'t> {
51 if pos >= self.tokens.len() { 51 if pos >= self.tokens.len() {
52 return false; 52 return false;
53 } 53 }
54 let range = TextRange::offset_len(self.start_offsets[pos], self.tokens[pos].len); 54 let range = TextRange::at(self.start_offsets[pos], self.tokens[pos].len);
55 self.text[range] == *kw 55 self.text[range] == *kw
56 } 56 }
57} 57}
58 58
59fn mk_token(pos: usize, start_offsets: &[TextUnit], tokens: &[Token]) -> PToken { 59fn mk_token(pos: usize, start_offsets: &[TextSize], tokens: &[Token]) -> PToken {
60 let kind = tokens.get(pos).map(|t| t.kind).unwrap_or(EOF); 60 let kind = tokens.get(pos).map(|t| t.kind).unwrap_or(EOF);
61 let is_jointed_to_next = if pos + 1 < start_offsets.len() { 61 let is_jointed_to_next = if pos + 1 < start_offsets.len() {
62 start_offsets[pos] + tokens[pos].len == start_offsets[pos + 1] 62 start_offsets[pos] + tokens[pos].len == start_offsets[pos + 1]
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index 87bb21cd9..22aed1db1 100644
--- a/crates/ra_syntax/src/parsing/text_tree_sink.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -9,7 +9,7 @@ use crate::{
9 syntax_node::GreenNode, 9 syntax_node::GreenNode,
10 SmolStr, SyntaxError, 10 SmolStr, SyntaxError,
11 SyntaxKind::{self, *}, 11 SyntaxKind::{self, *},
12 SyntaxTreeBuilder, TextRange, TextUnit, 12 SyntaxTreeBuilder, TextRange, TextSize,
13}; 13};
14 14
15/// Bridges the parser with our specific syntax tree representation. 15/// Bridges the parser with our specific syntax tree representation.
@@ -18,7 +18,7 @@ use crate::{
18pub(crate) struct TextTreeSink<'a> { 18pub(crate) struct TextTreeSink<'a> {
19 text: &'a str, 19 text: &'a str,
20 tokens: &'a [Token], 20 tokens: &'a [Token],
21 text_pos: TextUnit, 21 text_pos: TextSize,
22 token_pos: usize, 22 token_pos: usize,
23 state: State, 23 state: State,
24 inner: SyntaxTreeBuilder, 24 inner: SyntaxTreeBuilder,
@@ -42,7 +42,7 @@ impl<'a> TreeSink for TextTreeSink<'a> {
42 let len = self.tokens[self.token_pos..self.token_pos + n_tokens] 42 let len = self.tokens[self.token_pos..self.token_pos + n_tokens]
43 .iter() 43 .iter()
44 .map(|it| it.len) 44 .map(|it| it.len)
45 .sum::<TextUnit>(); 45 .sum::<TextSize>();
46 self.do_token(kind, len, n_tokens); 46 self.do_token(kind, len, n_tokens);
47 } 47 }
48 48
@@ -62,12 +62,12 @@ impl<'a> TreeSink for TextTreeSink<'a> {
62 self.tokens[self.token_pos..].iter().take_while(|it| it.kind.is_trivia()).count(); 62 self.tokens[self.token_pos..].iter().take_while(|it| it.kind.is_trivia()).count();
63 let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias]; 63 let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias];
64 let mut trivia_end = 64 let mut trivia_end =
65 self.text_pos + leading_trivias.iter().map(|it| it.len).sum::<TextUnit>(); 65 self.text_pos + leading_trivias.iter().map(|it| it.len).sum::<TextSize>();
66 66
67 let n_attached_trivias = { 67 let n_attached_trivias = {
68 let leading_trivias = leading_trivias.iter().rev().map(|it| { 68 let leading_trivias = leading_trivias.iter().rev().map(|it| {
69 let next_end = trivia_end - it.len; 69 let next_end = trivia_end - it.len;
70 let range = TextRange::from_to(next_end, trivia_end); 70 let range = TextRange::new(next_end, trivia_end);
71 trivia_end = next_end; 71 trivia_end = next_end;
72 (it.kind, &self.text[range]) 72 (it.kind, &self.text[range])
73 }); 73 });
@@ -132,8 +132,8 @@ impl<'a> TextTreeSink<'a> {
132 } 132 }
133 } 133 }
134 134
135 fn do_token(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { 135 fn do_token(&mut self, kind: SyntaxKind, len: TextSize, n_tokens: usize) {
136 let range = TextRange::offset_len(self.text_pos, len); 136 let range = TextRange::at(self.text_pos, len);
137 let text: SmolStr = self.text[range].into(); 137 let text: SmolStr = self.text[range].into();
138 self.text_pos += len; 138 self.text_pos += len;
139 self.token_pos += n_tokens; 139 self.token_pos += n_tokens;
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index ecbfffcf4..62f03e93d 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -24,7 +24,7 @@ impl SyntaxNodePtr {
24 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode { 24 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
25 assert!(root.parent().is_none()); 25 assert!(root.parent().is_none());
26 successors(Some(root.clone()), |node| { 26 successors(Some(root.clone()), |node| {
27 node.children().find(|it| self.range.is_subrange(&it.text_range())) 27 node.children().find(|it| it.text_range().contains_range(self.range))
28 }) 28 })
29 .find(|it| it.text_range() == self.range && it.kind() == self.kind) 29 .find(|it| it.text_range() == self.range && it.kind() == self.kind)
30 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) 30 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index 54acf7847..7c4511fec 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -2,7 +2,7 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use crate::{TextRange, TextUnit}; 5use crate::{TextRange, TextSize};
6 6
7/// Represents the result of unsuccessful tokenization, parsing 7/// Represents the result of unsuccessful tokenization, parsing
8/// or tree validation. 8/// or tree validation.
@@ -23,8 +23,8 @@ impl SyntaxError {
23 pub fn new(message: impl Into<String>, range: TextRange) -> Self { 23 pub fn new(message: impl Into<String>, range: TextRange) -> Self {
24 Self(message.into(), range) 24 Self(message.into(), range)
25 } 25 }
26 pub fn new_at_offset(message: impl Into<String>, offset: TextUnit) -> Self { 26 pub fn new_at_offset(message: impl Into<String>, offset: TextSize) -> Self {
27 Self(message.into(), TextRange::offset_len(offset, 0.into())) 27 Self(message.into(), TextRange::empty(offset))
28 } 28 }
29 29
30 pub fn range(&self) -> TextRange { 30 pub fn range(&self) -> TextRange {
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 4e3a1460d..f9d379abf 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -8,7 +8,7 @@
8 8
9use rowan::{GreenNodeBuilder, Language}; 9use rowan::{GreenNodeBuilder, Language};
10 10
11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextUnit}; 11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize};
12 12
13pub(crate) use rowan::{GreenNode, GreenToken}; 13pub(crate) use rowan::{GreenNode, GreenToken};
14 14
@@ -69,7 +69,7 @@ impl SyntaxTreeBuilder {
69 self.inner.finish_node() 69 self.inner.finish_node()
70 } 70 }
71 71
72 pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextUnit) { 72 pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextSize) {
73 self.errors.push(SyntaxError::new_at_offset(error.0, text_pos)) 73 self.errors.push(SyntaxError::new_at_offset(error.0, text_pos))
74 } 74 }
75} 75}
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index 355843b94..4f2b67feb 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -5,7 +5,7 @@ use std::{
5 5
6use test_utils::{collect_rust_files, dir_tests, project_dir, read_text}; 6use test_utils::{collect_rust_files, dir_tests, project_dir, read_text};
7 7
8use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextUnit, Token}; 8use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token};
9 9
10#[test] 10#[test]
11fn lexer_tests() { 11fn lexer_tests() {
@@ -121,12 +121,12 @@ fn assert_errors_are_absent(errors: &[SyntaxError], path: &Path) {
121 121
122fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) -> String { 122fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) -> String {
123 let mut acc = String::new(); 123 let mut acc = String::new();
124 let mut offset = TextUnit::from_usize(0); 124 let mut offset = TextSize::from_usize(0);
125 for token in tokens { 125 for token in tokens {
126 let token_len = token.len; 126 let token_len = token.len;
127 let token_text = &text[TextRange::offset_len(offset, token.len)]; 127 let token_text = &text[TextRange::at(offset, token.len)];
128 offset += token.len; 128 offset += token.len;
129 writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap(); 129 writeln!(acc, "{:?} {:?} {:?}", token.kind, token_len, token_text).unwrap();
130 } 130 }
131 for err in errors { 131 for err in errors {
132 writeln!(acc, "> error{:?} token({:?}) msg({})", err.range(), &text[err.range()], err) 132 writeln!(acc, "> error{:?} token({:?}) msg({})", err.range(), &text[err.range()], err)
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index f85b3e61b..77d7e132d 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -7,7 +7,7 @@ use rustc_lexer::unescape;
7use crate::{ 7use crate::{
8 ast, match_ast, AstNode, SyntaxError, 8 ast, match_ast, AstNode, SyntaxError,
9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, 9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF},
10 SyntaxNode, SyntaxToken, TextUnit, T, 10 SyntaxNode, SyntaxToken, TextSize, T,
11}; 11};
12 12
13fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { 13fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str {
@@ -112,7 +112,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
112 112
113 // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205) 113 // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205)
114 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { 114 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| {
115 let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len); 115 let off = token.text_range().start() + TextSize::from_usize(off + prefix_len);
116 acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off)); 116 acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
117 }; 117 };
118 118
diff --git a/crates/ra_text_edit/Cargo.toml b/crates/ra_text_edit/Cargo.toml
index cae28389d..9b0567c98 100644
--- a/crates/ra_text_edit/Cargo.toml
+++ b/crates/ra_text_edit/Cargo.toml
@@ -9,5 +9,4 @@ publish = false
9doctest = false 9doctest = false
10 10
11[dependencies] 11[dependencies]
12text_unit = "0.1.10" 12text-size = { path = "../../../text-size" }
13
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs
index f6769e6a6..e656260c7 100644
--- a/crates/ra_text_edit/src/lib.rs
+++ b/crates/ra_text_edit/src/lib.rs
@@ -2,7 +2,7 @@
2 2
3mod text_edit; 3mod text_edit;
4 4
5use text_unit::{TextRange, TextUnit}; 5use text_size::{TextRange, TextSize};
6 6
7pub use crate::text_edit::{TextEdit, TextEditBuilder}; 7pub use crate::text_edit::{TextEdit, TextEditBuilder};
8 8
@@ -23,13 +23,13 @@ impl AtomTextEdit {
23 AtomTextEdit::replace(range, String::new()) 23 AtomTextEdit::replace(range, String::new())
24 } 24 }
25 25
26 pub fn insert(offset: TextUnit, text: String) -> AtomTextEdit { 26 pub fn insert(offset: TextSize, text: String) -> AtomTextEdit {
27 AtomTextEdit::replace(TextRange::offset_len(offset, 0.into()), text) 27 AtomTextEdit::replace(TextRange::empty(offset), text)
28 } 28 }
29 29
30 pub fn apply(&self, mut text: String) -> String { 30 pub fn apply(&self, mut text: String) -> String {
31 let start = self.delete.start().to_usize(); 31 let start: usize = self.delete.start().into();
32 let end = self.delete.end().to_usize(); 32 let end: usize = self.delete.end().into();
33 text.replace_range(start..end, &self.insert); 33 text.replace_range(start..end, &self.insert);
34 text 34 text
35 } 35 }
diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs
index 5c37a08a8..db69a7e7b 100644
--- a/crates/ra_text_edit/src/text_edit.rs
+++ b/crates/ra_text_edit/src/text_edit.rs
@@ -1,7 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::AtomTextEdit; 3use crate::AtomTextEdit;
4use text_unit::{TextRange, TextUnit}; 4// TODO: fix Cargo.toml
5use text_size::{TextRange, TextSize};
5 6
6#[derive(Debug, Clone)] 7#[derive(Debug, Clone)]
7pub struct TextEdit { 8pub struct TextEdit {
@@ -20,19 +21,19 @@ impl TextEditBuilder {
20 pub fn delete(&mut self, range: TextRange) { 21 pub fn delete(&mut self, range: TextRange) {
21 self.atoms.push(AtomTextEdit::delete(range)) 22 self.atoms.push(AtomTextEdit::delete(range))
22 } 23 }
23 pub fn insert(&mut self, offset: TextUnit, text: String) { 24 pub fn insert(&mut self, offset: TextSize, text: String) {
24 self.atoms.push(AtomTextEdit::insert(offset, text)) 25 self.atoms.push(AtomTextEdit::insert(offset, text))
25 } 26 }
26 pub fn finish(self) -> TextEdit { 27 pub fn finish(self) -> TextEdit {
27 TextEdit::from_atoms(self.atoms) 28 TextEdit::from_atoms(self.atoms)
28 } 29 }
29 pub fn invalidates_offset(&self, offset: TextUnit) -> bool { 30 pub fn invalidates_offset(&self, offset: TextSize) -> bool {
30 self.atoms.iter().any(|atom| atom.delete.contains_inclusive(offset)) 31 self.atoms.iter().any(|atom| atom.delete.contains_inclusive(offset))
31 } 32 }
32} 33}
33 34
34impl TextEdit { 35impl TextEdit {
35 pub fn insert(offset: TextUnit, text: String) -> TextEdit { 36 pub fn insert(offset: TextSize, text: String) -> TextEdit {
36 let mut builder = TextEditBuilder::default(); 37 let mut builder = TextEditBuilder::default();
37 builder.insert(offset, text); 38 builder.insert(offset, text);
38 builder.finish() 39 builder.finish()
@@ -63,16 +64,16 @@ impl TextEdit {
63 } 64 }
64 65
65 pub fn apply(&self, text: &str) -> String { 66 pub fn apply(&self, text: &str) -> String {
66 let mut total_len = TextUnit::of_str(text); 67 let mut total_len = TextSize::of(text);
67 for atom in self.atoms.iter() { 68 for atom in self.atoms.iter() {
68 total_len += TextUnit::of_str(&atom.insert); 69 total_len += TextSize::of(&atom.insert);
69 total_len -= atom.delete.end() - atom.delete.start(); 70 total_len -= atom.delete.end() - atom.delete.start();
70 } 71 }
71 let mut buf = String::with_capacity(total_len.to_usize()); 72 let mut buf = String::with_capacity(total_len.into());
72 let mut prev = 0; 73 let mut prev = 0;
73 for atom in self.atoms.iter() { 74 for atom in self.atoms.iter() {
74 let start = atom.delete.start().to_usize(); 75 let start: usize = atom.delete.start().into();
75 let end = atom.delete.end().to_usize(); 76 let end: usize = atom.delete.end().into();
76 if start > prev { 77 if start > prev {
77 buf.push_str(&text[prev..start]); 78 buf.push_str(&text[prev..start]);
78 } 79 }
@@ -80,11 +81,11 @@ impl TextEdit {
80 prev = end; 81 prev = end;
81 } 82 }
82 buf.push_str(&text[prev..text.len()]); 83 buf.push_str(&text[prev..text.len()]);
83 assert_eq!(TextUnit::of_str(&buf), total_len); 84 assert_eq!(TextSize::of(&buf), total_len);
84 buf 85 buf
85 } 86 }
86 87
87 pub fn apply_to_offset(&self, offset: TextUnit) -> Option<TextUnit> { 88 pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> {
88 let mut res = offset; 89 let mut res = offset;
89 for atom in self.atoms.iter() { 90 for atom in self.atoms.iter() {
90 if atom.delete.start() >= offset { 91 if atom.delete.start() >= offset {
@@ -93,7 +94,7 @@ impl TextEdit {
93 if offset < atom.delete.end() { 94 if offset < atom.delete.end() {
94 return None; 95 return None;
95 } 96 }
96 res += TextUnit::of_str(&atom.insert); 97 res += TextSize::of(&atom.insert);
97 res -= atom.delete.len(); 98 res -= atom.delete.len();
98 } 99 }
99 Some(res) 100 Some(res)
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9fa7dad71..72183da15 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -130,7 +130,7 @@ pub fn analysis_stats(
130 let original_file = src.file_id.original_file(db); 130 let original_file = src.file_id.original_file(db);
131 let path = db.file_relative_path(original_file); 131 let path = db.file_relative_path(original_file);
132 let syntax_range = src.value.syntax().text_range(); 132 let syntax_range = src.value.syntax().text_range();
133 format_to!(msg, " ({:?} {})", path, syntax_range); 133 format_to!(msg, " ({:?} {:?})", path, syntax_range);
134 } 134 }
135 if verbosity.is_spammy() { 135 if verbosity.is_spammy() {
136 bar.println(msg.to_string()); 136 bar.println(msg.to_string());
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs
index 2285cb1d3..b0f911f71 100644
--- a/crates/rust-analyzer/src/conv.rs
+++ b/crates/rust-analyzer/src/conv.rs
@@ -14,7 +14,7 @@ use ra_ide::{
14 InlayHint, InlayKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, 14 InlayHint, InlayKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo,
15 ReferenceAccess, Severity, SourceChange, SourceFileEdit, 15 ReferenceAccess, Severity, SourceChange, SourceFileEdit,
16}; 16};
17use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 17use ra_syntax::{SyntaxKind, TextRange, TextSize};
18use ra_text_edit::{AtomTextEdit, TextEdit}; 18use ra_text_edit::{AtomTextEdit, TextEdit};
19use ra_vfs::LineEndings; 19use ra_vfs::LineEndings;
20 20
@@ -124,13 +124,13 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
124 // LSP does not allow arbitrary edits in completion, so we have to do a 124 // LSP does not allow arbitrary edits in completion, so we have to do a
125 // non-trivial mapping here. 125 // non-trivial mapping here.
126 for atom_edit in self.text_edit().as_atoms() { 126 for atom_edit in self.text_edit().as_atoms() {
127 if self.source_range().is_subrange(&atom_edit.delete) { 127 if atom_edit.delete.contains_range(self.source_range()) {
128 text_edit = Some(if atom_edit.delete == self.source_range() { 128 text_edit = Some(if atom_edit.delete == self.source_range() {
129 atom_edit.conv_with((ctx.0, ctx.1)) 129 atom_edit.conv_with((ctx.0, ctx.1))
130 } else { 130 } else {
131 assert!(self.source_range().end() == atom_edit.delete.end()); 131 assert!(self.source_range().end() == atom_edit.delete.end());
132 let range1 = 132 let range1 =
133 TextRange::from_to(atom_edit.delete.start(), self.source_range().start()); 133 TextRange::new(atom_edit.delete.start(), self.source_range().start());
134 let range2 = self.source_range(); 134 let range2 = self.source_range();
135 let edit1 = AtomTextEdit::replace(range1, String::new()); 135 let edit1 = AtomTextEdit::replace(range1, String::new());
136 let edit2 = AtomTextEdit::replace(range2, atom_edit.insert.clone()); 136 let edit2 = AtomTextEdit::replace(range2, atom_edit.insert.clone());
@@ -138,7 +138,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
138 edit2.conv_with((ctx.0, ctx.1)) 138 edit2.conv_with((ctx.0, ctx.1))
139 }) 139 })
140 } else { 140 } else {
141 assert!(self.source_range().intersection(&atom_edit.delete).is_none()); 141 assert!(self.source_range().intersect(atom_edit.delete).is_none());
142 additional_text_edits.push(atom_edit.conv_with((ctx.0, ctx.1))); 142 additional_text_edits.push(atom_edit.conv_with((ctx.0, ctx.1)));
143 } 143 }
144 } 144 }
@@ -184,15 +184,15 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
184} 184}
185 185
186impl ConvWith<&LineIndex> for Position { 186impl ConvWith<&LineIndex> for Position {
187 type Output = TextUnit; 187 type Output = TextSize;
188 188
189 fn conv_with(self, line_index: &LineIndex) -> TextUnit { 189 fn conv_with(self, line_index: &LineIndex) -> TextSize {
190 let line_col = LineCol { line: self.line as u32, col_utf16: self.character as u32 }; 190 let line_col = LineCol { line: self.line as u32, col_utf16: self.character as u32 };
191 line_index.offset(line_col) 191 line_index.offset(line_col)
192 } 192 }
193} 193}
194 194
195impl ConvWith<&LineIndex> for TextUnit { 195impl ConvWith<&LineIndex> for TextSize {
196 type Output = Position; 196 type Output = Position;
197 197
198 fn conv_with(self, line_index: &LineIndex) -> Position { 198 fn conv_with(self, line_index: &LineIndex) -> Position {
@@ -213,7 +213,7 @@ impl ConvWith<&LineIndex> for Range {
213 type Output = TextRange; 213 type Output = TextRange;
214 214
215 fn conv_with(self, line_index: &LineIndex) -> TextRange { 215 fn conv_with(self, line_index: &LineIndex) -> TextRange {
216 TextRange::from_to(self.start.conv_with(line_index), self.end.conv_with(line_index)) 216 TextRange::new(self.start.conv_with(line_index), self.end.conv_with(line_index))
217 } 217 }
218} 218}
219 219
@@ -300,7 +300,7 @@ impl ConvWith<&FoldConvCtx<'_>> for Fold {
300 // range.end.line from the folding region if there is more text after range.end 300 // range.end.line from the folding region if there is more text after range.end
301 // on the same line. 301 // on the same line.
302 let has_more_text_on_end_line = ctx.text 302 let has_more_text_on_end_line = ctx.text
303 [TextRange::from_to(self.range.end(), TextUnit::of_str(ctx.text))] 303 [TextRange::new(self.range.end(), TextSize::of(ctx.text))]
304 .chars() 304 .chars()
305 .take_while(|it| *it != '\n') 305 .take_while(|it| *it != '\n')
306 .any(|it| !it.is_whitespace()); 306 .any(|it| !it.is_whitespace());
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 41d9fe344..381f37f16 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -23,7 +23,7 @@ use ra_ide::{
23 SearchScope, 23 SearchScope,
24}; 24};
25use ra_prof::profile; 25use ra_prof::profile;
26use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; 26use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize};
27use rustc_hash::FxHashMap; 27use rustc_hash::FxHashMap;
28use serde::{Deserialize, Serialize}; 28use serde::{Deserialize, Serialize};
29use serde_json::to_value; 29use serde_json::to_value;
@@ -97,7 +97,7 @@ pub fn handle_selection_range(
97 .map(|position| { 97 .map(|position| {
98 let mut ranges = Vec::new(); 98 let mut ranges = Vec::new();
99 { 99 {
100 let mut range = TextRange::from_to(position, position); 100 let mut range = TextRange::new(position, position);
101 loop { 101 loop {
102 ranges.push(range); 102 ranges.push(range);
103 let frange = FileRange { file_id, range }; 103 let frange = FileRange { file_id, range };
@@ -184,11 +184,11 @@ pub fn handle_on_type_formatting(
184 184
185 // in `ra_ide`, the `on_type` invariant is that 185 // in `ra_ide`, the `on_type` invariant is that
186 // `text.char_at(position) == typed_char`. 186 // `text.char_at(position) == typed_char`.
187 position.offset -= TextUnit::of_char('.'); 187 position.offset -= TextSize::of('.');
188 let char_typed = params.ch.chars().next().unwrap_or('\0'); 188 let char_typed = params.ch.chars().next().unwrap_or('\0');
189 assert!({ 189 assert!({
190 let text = world.analysis().file_text(position.file_id)?; 190 let text = world.analysis().file_text(position.file_id)?;
191 text[position.offset.to_usize()..].starts_with(char_typed) 191 text[usize::from(position.offset)..].starts_with(char_typed)
192 }); 192 });
193 193
194 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, 194 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
@@ -403,7 +403,7 @@ pub fn handle_completion(
403 let syntax = source_file.syntax(); 403 let syntax = source_file.syntax();
404 let text = syntax.text(); 404 let text = syntax.text();
405 if let Some(next_char) = text.char_at(position.offset) { 405 if let Some(next_char) = text.char_at(position.offset) {
406 let diff = TextUnit::of_char(next_char) + TextUnit::of_char(':'); 406 let diff = TextSize::of(next_char) + TextSize::of(':');
407 let prev_char = position.offset - diff; 407 let prev_char = position.offset - diff;
408 if text.char_at(prev_char) != Some(':') { 408 if text.char_at(prev_char) != Some(':') {
409 res = true; 409 res = true;
@@ -592,7 +592,7 @@ pub fn handle_formatting(
592 let crate_ids = world.analysis().crate_for(file_id)?; 592 let crate_ids = world.analysis().crate_for(file_id)?;
593 593
594 let file_line_index = world.analysis().file_line_index(file_id)?; 594 let file_line_index = world.analysis().file_line_index(file_id)?;
595 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); 595 let end_position = TextSize::of(&file).conv_with(&file_line_index);
596 596
597 let mut rustfmt = match &world.config.rustfmt { 597 let mut rustfmt = match &world.config.rustfmt {
598 RustfmtConfig::Rustfmt { extra_args } => { 598 RustfmtConfig::Rustfmt { extra_args } => {
@@ -698,7 +698,7 @@ pub fn handle_code_action(
698 let fixes_from_diagnostics = diagnostics 698 let fixes_from_diagnostics = diagnostics
699 .into_iter() 699 .into_iter()
700 .filter_map(|d| Some((d.range, d.fix?))) 700 .filter_map(|d| Some((d.range, d.fix?)))
701 .filter(|(diag_range, _fix)| diag_range.intersection(&range).is_some()) 701 .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some())
702 .map(|(_range, fix)| fix); 702 .map(|(_range, fix)| fix);
703 703
704 for source_edit in fixes_from_diagnostics { 704 for source_edit in fixes_from_diagnostics {
@@ -723,7 +723,7 @@ pub fn handle_code_action(
723 723
724 for fix in world.check_fixes.get(&file_id).into_iter().flatten() { 724 for fix in world.check_fixes.get(&file_id).into_iter().flatten() {
725 let fix_range = fix.range.conv_with(&line_index); 725 let fix_range = fix.range.conv_with(&line_index);
726 if fix_range.intersection(&range).is_none() { 726 if fix_range.intersect(range).is_none() {
727 continue; 727 continue;
728 } 728 }
729 res.push(fix.action.clone()); 729 res.push(fix.action.clone());
@@ -1107,7 +1107,7 @@ pub fn handle_semantic_tokens(
1107 let (token_index, modifier_bitset) = highlight_range.highlight.conv(); 1107 let (token_index, modifier_bitset) = highlight_range.highlight.conv();
1108 for mut range in line_index.lines(highlight_range.range) { 1108 for mut range in line_index.lines(highlight_range.range) {
1109 if text[range].ends_with('\n') { 1109 if text[range].ends_with('\n') {
1110 range = TextRange::from_to(range.start(), range.end() - TextUnit::of_char('\n')); 1110 range = TextRange::new(range.start(), range.end() - TextSize::of('\n'));
1111 } 1111 }
1112 let range = range.conv_with(&line_index); 1112 let range = range.conv_with(&line_index);
1113 builder.push(range, token_index, modifier_bitset); 1113 builder.push(range, token_index, modifier_bitset);
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 6a7c6d6f9..652ab4537 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -9,5 +9,5 @@ doctest = false
9 9
10[dependencies] 10[dependencies]
11difference = "2.0.0" 11difference = "2.0.0"
12text_unit = "0.1.10" 12text-size = { path = "../../../text-size" }
13serde_json = "1.0.48" 13serde_json = "1.0.48"
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 4164bfd5e..b1365444a 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -15,7 +15,7 @@ use std::{
15}; 15};
16 16
17use serde_json::Value; 17use serde_json::Value;
18use text_unit::{TextRange, TextUnit}; 18use text_size::{TextRange, TextSize};
19 19
20pub use difference::Changeset as __Changeset; 20pub use difference::Changeset as __Changeset;
21 21
@@ -49,7 +49,7 @@ macro_rules! assert_eq_text {
49} 49}
50 50
51/// Infallible version of `try_extract_offset()`. 51/// Infallible version of `try_extract_offset()`.
52pub fn extract_offset(text: &str) -> (TextUnit, String) { 52pub fn extract_offset(text: &str) -> (TextSize, String) {
53 match try_extract_offset(text) { 53 match try_extract_offset(text) {
54 None => panic!("text should contain cursor marker"), 54 None => panic!("text should contain cursor marker"),
55 Some(result) => result, 55 Some(result) => result,
@@ -58,12 +58,12 @@ pub fn extract_offset(text: &str) -> (TextUnit, String) {
58 58
59/// Returns the offset of the first occurence of `<|>` marker and the copy of `text` 59/// Returns the offset of the first occurence of `<|>` marker and the copy of `text`
60/// without the marker. 60/// without the marker.
61fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> { 61fn try_extract_offset(text: &str) -> Option<(TextSize, String)> {
62 let cursor_pos = text.find(CURSOR_MARKER)?; 62 let cursor_pos = text.find(CURSOR_MARKER)?;
63 let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len()); 63 let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len());
64 new_text.push_str(&text[..cursor_pos]); 64 new_text.push_str(&text[..cursor_pos]);
65 new_text.push_str(&text[cursor_pos + CURSOR_MARKER.len()..]); 65 new_text.push_str(&text[cursor_pos + CURSOR_MARKER.len()..]);
66 let cursor_pos = TextUnit::from(cursor_pos as u32); 66 let cursor_pos = TextSize::from(cursor_pos as u32);
67 Some((cursor_pos, new_text)) 67 Some((cursor_pos, new_text))
68} 68}
69 69
@@ -80,25 +80,25 @@ pub fn extract_range(text: &str) -> (TextRange, String) {
80fn try_extract_range(text: &str) -> Option<(TextRange, String)> { 80fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
81 let (start, text) = try_extract_offset(text)?; 81 let (start, text) = try_extract_offset(text)?;
82 let (end, text) = try_extract_offset(&text)?; 82 let (end, text) = try_extract_offset(&text)?;
83 Some((TextRange::from_to(start, end), text)) 83 Some((TextRange::new(start, end), text))
84} 84}
85 85
86#[derive(Clone, Copy)] 86#[derive(Clone, Copy)]
87pub enum RangeOrOffset { 87pub enum RangeOrOffset {
88 Range(TextRange), 88 Range(TextRange),
89 Offset(TextUnit), 89 Offset(TextSize),
90} 90}
91 91
92impl From<RangeOrOffset> for TextRange { 92impl From<RangeOrOffset> for TextRange {
93 fn from(selection: RangeOrOffset) -> Self { 93 fn from(selection: RangeOrOffset) -> Self {
94 match selection { 94 match selection {
95 RangeOrOffset::Range(it) => it, 95 RangeOrOffset::Range(it) => it,
96 RangeOrOffset::Offset(it) => TextRange::from_to(it, it), 96 RangeOrOffset::Offset(it) => TextRange::new(it, it),
97 } 97 }
98 } 98 }
99} 99}
100 100
101/// Extracts `TextRange` or `TextUnit` depending on the amount of `<|>` markers 101/// Extracts `TextRange` or `TextSize` depending on the amount of `<|>` markers
102/// found in `text`. 102/// found in `text`.
103/// 103///
104/// # Panics 104/// # Panics
@@ -129,13 +129,13 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
129 text = &text[i..]; 129 text = &text[i..];
130 if text.starts_with(&open) { 130 if text.starts_with(&open) {
131 text = &text[open.len()..]; 131 text = &text[open.len()..];
132 let from = TextUnit::of_str(&res); 132 let from = TextSize::of(&res);
133 stack.push(from); 133 stack.push(from);
134 } else if text.starts_with(&close) { 134 } else if text.starts_with(&close) {
135 text = &text[close.len()..]; 135 text = &text[close.len()..];
136 let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag)); 136 let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
137 let to = TextUnit::of_str(&res); 137 let to = TextSize::of(&res);
138 ranges.push(TextRange::from_to(from, to)); 138 ranges.push(TextRange::new(from, to));
139 } 139 }
140 } 140 }
141 } 141 }
@@ -146,8 +146,8 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
146} 146}
147 147
148/// Inserts `<|>` marker into the `text` at `offset`. 148/// Inserts `<|>` marker into the `text` at `offset`.
149pub fn add_cursor(text: &str, offset: TextUnit) -> String { 149pub fn add_cursor(text: &str, offset: TextSize) -> String {
150 let offset: usize = offset.to_usize(); 150 let offset: usize = offset.into();
151 let mut res = String::new(); 151 let mut res = String::new();
152 res.push_str(&text[..offset]); 152 res.push_str(&text[..offset]);
153 res.push_str("<|>"); 153 res.push_str("<|>");
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
index 0a4554c55..e138c656a 100644
--- a/docs/dev/syntax.md
+++ b/docs/dev/syntax.md
@@ -17,7 +17,7 @@ The things described are implemented in two places
17 17
18* Syntax trees are lossless, or full fidelity. All comments and whitespace are preserved. 18* Syntax trees are lossless, or full fidelity. All comments and whitespace are preserved.
19* Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached. 19* Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached.
20* Syntax trees are simple value type. It is possible to create trees for a syntax without any external context. 20* Syntax trees are simple value type. It is possible to create trees for a syntax without any external context.
21* Syntax trees have intuitive traversal API (parent, children, siblings, etc). 21* Syntax trees have intuitive traversal API (parent, children, siblings, etc).
22* Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly). 22* Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly).
23* Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can). 23* Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can).
@@ -34,12 +34,12 @@ The syntax tree consists of three layers:
34* SyntaxNodes (aka RedNode) 34* SyntaxNodes (aka RedNode)
35* AST 35* AST
36 36
37Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree. 37Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree.
38Red-green terminology comes from Roslyn ([link](https://docs.microsoft.com/en-ie/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer. 38Red-green terminology comes from Roslyn ([link](https://docs.microsoft.com/en-ie/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer.
39 39
40Syntax trees are a semi-transient data structure. 40Syntax trees are a semi-transient data structure.
41In general, frontend does not keep syntax trees for all files in memory. 41In general, frontend does not keep syntax trees for all files in memory.
42Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired. 42Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired.
43 43
44 44
45### GreenNode 45### GreenNode
@@ -64,7 +64,7 @@ struct Token {
64} 64}
65``` 65```
66 66
67All the difference bettwen the above sketch and the real implementation are strictly due to optimizations. 67All the difference bettwen the above sketch and the real implementation are strictly due to optimizations.
68 68
69Points of note: 69Points of note:
70* The tree is untyped. Each node has a "type tag", `SyntaxKind`. 70* The tree is untyped. Each node has a "type tag", `SyntaxKind`.
@@ -73,7 +73,7 @@ Points of note:
73* Each token carries its full text. 73* Each token carries its full text.
74* The original text can be recovered by concatenating the texts of all tokens in order. 74* The original text can be recovered by concatenating the texts of all tokens in order.
75* Accessing a child of particular type (for example, parameter list of a function) generarly involves linerary traversing the children, looking for a specific `kind`. 75* Accessing a child of particular type (for example, parameter list of a function) generarly involves linerary traversing the children, looking for a specific `kind`.
76* Modifying the tree is roughly `O(depth)`. 76* Modifying the tree is roughly `O(depth)`.
77 We don't make special efforts to guarantree that the depth is not liner, but, in practice, syntax trees are branchy and shallow. 77 We don't make special efforts to guarantree that the depth is not liner, but, in practice, syntax trees are branchy and shallow.
78* If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. 78* If mandatory (grammar wise) node is missing from the input, it's just missing from the tree.
79* If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. 79* If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node.
@@ -122,20 +122,20 @@ To reduce the amount of allocations, the GreenNode is a DST, which uses a single
122To more compactly store the children, we box *both* interior nodes and tokens, and represent 122To more compactly store the children, we box *both* interior nodes and tokens, and represent
123`Either<Arc<Node>, Arc<Token>>` as a single pointer with a tag in the last bit. 123`Either<Arc<Node>, Arc<Token>>` as a single pointer with a tag in the last bit.
124 124
125To avoid allocating EVERY SINGLE TOKEN on the heap, syntax trees use interning. 125To avoid allocating EVERY SINGLE TOKEN on the heap, syntax trees use interning.
126Because the tree is fully imutable, it's valid to structuraly share subtrees. 126Because the tree is fully imutable, it's valid to structuraly share subtrees.
127For example, in `1 + 1`, there will be a *single* token for `1` with ref count 2; the same goes for the ` ` whitespace token. 127For example, in `1 + 1`, there will be a *single* token for `1` with ref count 2; the same goes for the ` ` whitespace token.
128Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`). 128Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`).
129 129
130Note that, the result of the interning is an `Arc<Node>`. 130Note that, the result of the interning is an `Arc<Node>`.
131That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree. 131That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree.
132Each tree is fully self-contained (although different trees might share parts). 132Each tree is fully self-contained (although different trees might share parts).
133Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one. 133Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one.
134 134
135We use a `TextUnit`, a newtyped `u32`, to store the length of the text. 135We use a `TextSize`, a newtyped `u32`, to store the length of the text.
136 136
137We currently use `SmolStr`, an small object optimized string to store text. 137We currently use `SmolStr`, an small object optimized string to store text.
138This was mostly relevant *before* we implmented tree interning, to avoid allocating common keywords and identifiers. We should switch to storing text data alongside the interned tokens. 138This was mostly relevant *before* we implmented tree interning, to avoid allocating common keywords and identifiers. We should switch to storing text data alongside the interned tokens.
139 139
140#### Alternative designs 140#### Alternative designs
141 141
@@ -153,9 +153,9 @@ struct Token {
153} 153}
154``` 154```
155 155
156The tree then contains only non-trivia tokens. 156The tree then contains only non-trivia tokens.
157 157
158Another approach (from Dart) is to, in addition to a syntax tree, link all the tokens into a bidirectional link list. 158Another approach (from Dart) is to, in addition to a syntax tree, link all the tokens into a bidirectional link list.
159That way, the tree again contains only non-trivia tokens. 159That way, the tree again contains only non-trivia tokens.
160 160
161Explicit trivia nodes, like in `rowan`, are used by IntelliJ. 161Explicit trivia nodes, like in `rowan`, are used by IntelliJ.
@@ -165,26 +165,26 @@ Explicit trivia nodes, like in `rowan`, are used by IntelliJ.
165As noted before, accesing a specific child in the node requires a linear traversal of the children (though we can skip tokens, beacuse the tag is encoded in the pointer itself). 165As noted before, accesing a specific child in the node requires a linear traversal of the children (though we can skip tokens, beacuse the tag is encoded in the pointer itself).
166It is possible to recover O(1) access with another representation. 166It is possible to recover O(1) access with another representation.
167We explicitly store optional and missing (required by the grammar, but not present) nodes. 167We explicitly store optional and missing (required by the grammar, but not present) nodes.
168That is, we use `Option<Node>` for children. 168That is, we use `Option<Node>` for children.
169We also remove trivia tokens from the tree. 169We also remove trivia tokens from the tree.
170This way, each child kind genrerally occupies a fixed position in a parent, and we can use index access to fetch it. 170This way, each child kind genrerally occupies a fixed position in a parent, and we can use index access to fetch it.
171The cost is that we now need to allocate space for all not-present optional nodes. 171The cost is that we now need to allocate space for all not-present optional nodes.
172So, `fn foo() {}` will have slots for visibility, unsafeness, attributes, abi and return type. 172So, `fn foo() {}` will have slots for visibility, unsafeness, attributes, abi and return type.
173 173
174IntelliJ uses linear traversal. 174IntelliJ uses linear traversal.
175Roslyn and Swift do `O(1)` access. 175Roslyn and Swift do `O(1)` access.
176 176
177##### Mutable Trees 177##### Mutable Trees
178 178
179IntelliJ uses mutable trees. 179IntelliJ uses mutable trees.
180Overall, it creates a lot of additional complexity. 180Overall, it creates a lot of additional complexity.
181However, the API for *editing* syntax trees is nice. 181However, the API for *editing* syntax trees is nice.
182 182
183For example the assist to move generic bounds to where clause has this code: 183For example the assist to move generic bounds to where clause has this code:
184 184
185```kotlin 185```kotlin
186 for typeBound in typeBounds { 186 for typeBound in typeBounds {
187 typeBound.typeParamBounds?.delete() 187 typeBound.typeParamBounds?.delete()
188} 188}
189``` 189```
190 190
@@ -195,7 +195,7 @@ Modeling this with immutable trees is possible, but annoying.
195A function green tree is not super-convenient to use. 195A function green tree is not super-convenient to use.
196The biggest problem is acessing parents (there are no parent pointers!). 196The biggest problem is acessing parents (there are no parent pointers!).
197But there are also "identify" issues. 197But there are also "identify" issues.
198Let's say you want to write a code which builds a list of expressions in a file: `fn collect_exrepssions(file: GreenNode) -> HashSet<GreenNode>`. 198Let's say you want to write a code which builds a list of expressions in a file: `fn collect_exrepssions(file: GreenNode) -> HashSet<GreenNode>`.
199For the input like 199For the input like
200 200
201```rust 201```rust
@@ -233,7 +233,7 @@ impl SyntaxNode {
233 }) 233 })
234 } 234 }
235 fn parent(&self) -> Option<SyntaxNode> { 235 fn parent(&self) -> Option<SyntaxNode> {
236 self.parent.clone() 236 self.parent.clone()
237 } 237 }
238 fn children(&self) -> impl Iterator<Item = SyntaxNode> { 238 fn children(&self) -> impl Iterator<Item = SyntaxNode> {
239 let mut offset = self.offset 239 let mut offset = self.offset
@@ -251,8 +251,8 @@ impl SyntaxNode {
251 251
252impl PartialEq for SyntaxNode { 252impl PartialEq for SyntaxNode {
253 fn eq(&self, other: &SyntaxNode) { 253 fn eq(&self, other: &SyntaxNode) {
254 self.offset == other.offset 254 self.offset == other.offset
255 && Arc::ptr_eq(&self.green, &other.green) 255 && Arc::ptr_eq(&self.green, &other.green)
256 } 256 }
257} 257}
258``` 258```
@@ -261,35 +261,35 @@ Points of note:
261 261
262* SyntaxNode remembers its parent node (and, transitively, the path to the root of the tree) 262* SyntaxNode remembers its parent node (and, transitively, the path to the root of the tree)
263* SyntaxNode knows its *absolute* text offset in the whole file 263* SyntaxNode knows its *absolute* text offset in the whole file
264* Equality is based on identity. Comparing nodes from different trees does not make sense. 264* Equality is based on identity. Comparing nodes from different trees does not make sense.
265 265
266#### Optimization 266#### Optimization
267 267
268The reality is different though :-) 268The reality is different though :-)
269Traversal of trees is a common operation, and it makes sense to optimize it. 269Traversal of trees is a common operation, and it makes sense to optimize it.
270In particular, the above code allocates and does atomic operations during a traversal. 270In particular, the above code allocates and does atomic operations during a traversal.
271 271
272To get rid of atomics, `rowan` uses non thread-safe `Rc`. 272To get rid of atomics, `rowan` uses non thread-safe `Rc`.
273This is OK because trees traversals mostly (always, in case of rust-analyzer) run on a single thread. If you need to send a `SyntaxNode` to another thread, you can send a pair of **root**`GreenNode` (which is thread safe) and a `Range<usize>`. 273This is OK because trees traversals mostly (always, in case of rust-analyzer) run on a single thread. If you need to send a `SyntaxNode` to another thread, you can send a pair of **root**`GreenNode` (which is thread safe) and a `Range<usize>`.
274The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. 274The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
275You can also use the similar trick to store a `SyntaxNode`. 275You can also use the similar trick to store a `SyntaxNode`.
276That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. 276That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
277However rust-analyzer goes even further. 277However rust-analyzer goes even further.
278It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`. 278It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`.
279The `SyntaxNode` is the restored by reparsing the file and traversing it from root. 279The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
280With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. 280With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.
281 281
282Additionally, only the root `SyntaxNode` owns an `Arc` to the (root) `GreenNode`. 282Additionally, only the root `SyntaxNode` owns an `Arc` to the (root) `GreenNode`.
283All other `SyntaxNode`s point to corresponding `GreenNode`s with a raw pointer. 283All other `SyntaxNode`s point to corresponding `GreenNode`s with a raw pointer.
284They also point to the parent (and, consequently, to the root) with an owning `Rc`, so this is sound. 284They also point to the parent (and, consequently, to the root) with an owning `Rc`, so this is sound.
285In other words, one needs *one* arc bump when initiating a traversal. 285In other words, one needs *one* arc bump when initiating a traversal.
286 286
287To get rid of allocations, `rowan` takes advantage of `SyntaxNode: !Sync` and uses a thread-local free list of `SyntaxNode`s. 287To get rid of allocations, `rowan` takes advantage of `SyntaxNode: !Sync` and uses a thread-local free list of `SyntaxNode`s.
288In a typical traversal, you only directly hold a few `SyntaxNode`s at a time (and their ancesstors indirectly), so a free list proportional to the depth of the tree removes all allocations in a typical case. 288In a typical traversal, you only directly hold a few `SyntaxNode`s at a time (and their ancesstors indirectly), so a free list proportional to the depth of the tree removes all allocations in a typical case.
289 289
290So, while traversal is not exactly incrementing a pointer, it's still prety cheep: tls + rc bump! 290So, while traversal is not exactly incrementing a pointer, it's still prety cheep: tls + rc bump!
291 291
292Traversal also yields (cheap) owned nodes, which improves ergonomics quite a bit. 292Traversal also yields (cheap) owned nodes, which improves ergonomics quite a bit.
293 293
294#### Alternative Designs 294#### Alternative Designs
295 295
@@ -309,14 +309,14 @@ struct SyntaxData {
309``` 309```
310 310
311This allows using true pointer equality for comparision of identities of `SyntaxNodes`. 311This allows using true pointer equality for comparision of identities of `SyntaxNodes`.
312rust-analyzer used to have this design as well, but since we've switch to cursors. 312rust-analyzer used to have this design as well, but since we've switch to cursors.
313The main problem with memoizing the red nodes is that it more than doubles the memory requirenments for fully realized syntax trees. 313The main problem with memoizing the red nodes is that it more than doubles the memory requirenments for fully realized syntax trees.
314In contrast, cursors generally retain only a path to the root. 314In contrast, cursors generally retain only a path to the root.
315C# combats increased memory usage by using weak references. 315C# combats increased memory usage by using weak references.
316 316
317### AST 317### AST
318 318
319`GreenTree`s are untyped and homogeneous, because it makes accomodating error nodes, arbitrary whitespace and comments natural, and because it makes possible to write generic tree traversals. 319`GreenTree`s are untyped and homogeneous, because it makes accomodating error nodes, arbitrary whitespace and comments natural, and because it makes possible to write generic tree traversals.
320However, when working with a specific node, like a function definition, one would want a strongly typed API. 320However, when working with a specific node, like a function definition, one would want a strongly typed API.
321 321
322This is what is provided by the AST layer. AST nodes are transparent wrappers over untyped syntax nodes: 322This is what is provided by the AST layer. AST nodes are transparent wrappers over untyped syntax nodes:
@@ -352,13 +352,13 @@ impl AstNode for FnDef {
352} 352}
353 353
354impl FnDef { 354impl FnDef {
355 pub fn param_list(&self) -> Option<ParamList> { 355 pub fn param_list(&self) -> Option<ParamList> {
356 self.syntax.children().find_map(ParamList::cast) 356 self.syntax.children().find_map(ParamList::cast)
357 } 357 }
358 pub fn ret_type(&self) -> Option<RetType> { 358 pub fn ret_type(&self) -> Option<RetType> {
359 self.syntax.children().find_map(RetType::cast) 359 self.syntax.children().find_map(RetType::cast)
360 } 360 }
361 pub fn body(&self) -> Option<BlockExpr> { 361 pub fn body(&self) -> Option<BlockExpr> {
362 self.syntax.children().find_map(BlockExpr::cast) 362 self.syntax.children().find_map(BlockExpr::cast)
363 } 363 }
364 // ... 364 // ...
@@ -409,14 +409,14 @@ Points of note:
409 409
410##### Semantic Full AST 410##### Semantic Full AST
411 411
412In IntelliJ the AST layer (dubbed **P**rogram **S**tructure **I**nterface) can have semantics attached, and is usually backed by either syntax tree, indices, or metadata from compiled libraries. 412In IntelliJ the AST layer (dubbed **P**rogram **S**tructure **I**nterface) can have semantics attached, and is usually backed by either syntax tree, indices, or metadata from compiled libraries.
413The backend for PSI can change dynamically. 413The backend for PSI can change dynamically.
414 414
415### Syntax Tree Recap 415### Syntax Tree Recap
416 416
417At its core, the syntax tree is a purely functional n-ary tree, which stores text at the leaf nodes and node "kinds" at all nodes. 417At its core, the syntax tree is a purely functional n-ary tree, which stores text at the leaf nodes and node "kinds" at all nodes.
418A cursor layer is added on top, which gives owned, cheap to clone nodes with identity semantics, parent links and absolute offsets. 418A cursor layer is added on top, which gives owned, cheap to clone nodes with identity semantics, parent links and absolute offsets.
419An AST layer is added on top, which reifies each node `Kind` as a separate Rust type with the corresponding API. 419An AST layer is added on top, which reifies each node `Kind` as a separate Rust type with the corresponding API.
420 420
421## Parsing 421## Parsing
422 422
@@ -432,17 +432,17 @@ impl GreenNodeBuilder {
432 432
433 pub fn start_node(&mut self, kind: SyntaxKind) { ... } 433 pub fn start_node(&mut self, kind: SyntaxKind) { ... }
434 pub fn finish_node(&mut self) { ... } 434 pub fn finish_node(&mut self) { ... }
435 435
436 pub fn finish(self) -> GreenNode { ... } 436 pub fn finish(self) -> GreenNode { ... }
437} 437}
438``` 438```
439 439
440The parser, ultimatelly, needs to invoke the `GreenNodeBuilder`. 440The parser, ultimatelly, needs to invoke the `GreenNodeBuilder`.
441There are two principal sources of inputs for the parser: 441There are two principal sources of inputs for the parser:
442 * source text, which contains trivia tokens (whitespace and comments) 442 * source text, which contains trivia tokens (whitespace and comments)
443 * token trees from macros, which lack trivia 443 * token trees from macros, which lack trivia
444 444
445Additionaly, input tokens do not correspond 1-to-1 with output tokens. 445Additionaly, input tokens do not correspond 1-to-1 with output tokens.
446For example, two consequtive `>` tokens might be glued, by the parser, into a single `>>`. 446For example, two consequtive `>` tokens might be glued, by the parser, into a single `>>`.
447 447
448For these reasons, the parser crate defines a callback interfaces for both input tokens and output trees. 448For these reasons, the parser crate defines a callback interfaces for both input tokens and output trees.
@@ -474,7 +474,7 @@ pub trait TreeSink {
474} 474}
475 475
476pub fn parse( 476pub fn parse(
477 token_source: &mut dyn TokenSource, 477 token_source: &mut dyn TokenSource,
478 tree_sink: &mut dyn TreeSink, 478 tree_sink: &mut dyn TreeSink,
479) { ... } 479) { ... }
480``` 480```
@@ -491,21 +491,21 @@ Syntax errors are not stored directly in the tree.
491The primary motivation for this is that syntax tree is not necessary produced by the parser, it may also be assembled manually from pieces (which happens all the time in refactorings). 491The primary motivation for this is that syntax tree is not necessary produced by the parser, it may also be assembled manually from pieces (which happens all the time in refactorings).
492Instead, parser reports errors to an error sink, which stores them in a `Vec`. 492Instead, parser reports errors to an error sink, which stores them in a `Vec`.
493If possible, errors are not reported during parsing and are postponed for a separate validation step. 493If possible, errors are not reported during parsing and are postponed for a separate validation step.
494For example, parser accepts visibility modifiers on trait methods, but then a separate tree traversal flags all such visibilites as erroneous. 494For example, parser accepts visibility modifiers on trait methods, but then a separate tree traversal flags all such visibilites as erroneous.
495 495
496### Macros 496### Macros
497 497
498The primary difficulty with macros is that individual tokens have identities, which need to be preserved in the syntax tree for hygiene purposes. 498The primary difficulty with macros is that individual tokens have identities, which need to be preserved in the syntax tree for hygiene purposes.
499This is handled by the `TreeSink` layer. 499This is handled by the `TreeSink` layer.
500Specifically, `TreeSink` constructs the tree in lockstep with draining the original token stream. 500Specifically, `TreeSink` constructs the tree in lockstep with draining the original token stream.
501In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens. 501In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens.
502The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens. 502The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens.
503 503
504To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitelly handled by the parser 504To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitelly handled by the parser
505 505
506### Whitespace & Comments 506### Whitespace & Comments
507 507
508Parser does not see whitespace nodes. 508Parser does not see whitespace nodes.
509Instead, they are attached to the tree in the `TreeSink` layer. 509Instead, they are attached to the tree in the `TreeSink` layer.
510 510
511For example, in 511For example, in
@@ -521,7 +521,7 @@ the comment will be (heuristically) made a child of function node.
521 521
522Green trees are cheap to modify, so incremental reparse works by patching a previous tree, without maintaining any additional state. 522Green trees are cheap to modify, so incremental reparse works by patching a previous tree, without maintaining any additional state.
523The reparse is based on heuristic: we try to contain a change to a single `{}` block, and reparse only this block. 523The reparse is based on heuristic: we try to contain a change to a single `{}` block, and reparse only this block.
524To do this, we maintain the invariant that, even for invalid code, curly braces are always paired correctly. 524To do this, we maintain the invariant that, even for invalid code, curly braces are always paired correctly.
525 525
526In practice, incremental reparsing doesn't actually matter much for IDE use-cases, parsing from scratch seems to be fast enough. 526In practice, incremental reparsing doesn't actually matter much for IDE use-cases, parsing from scratch seems to be fast enough.
527 527