aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/utils/insert_use.rs2
-rw-r--r--crates/completion/src/completions.rs8
-rw-r--r--crates/completion/src/completions/unqualified_path.rs42
-rw-r--r--crates/completion/src/item.rs76
-rw-r--r--crates/completion/src/render.rs35
-rw-r--r--crates/completion/src/render/enum_variant.rs10
-rw-r--r--crates/completion/src/render/function.rs12
-rw-r--r--crates/completion/src/render/macro_.rs12
-rw-r--r--crates/text_edit/src/lib.rs4
9 files changed, 117 insertions, 84 deletions
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs
index 1aa727e11..423782a0e 100644
--- a/crates/assists/src/utils/insert_use.rs
+++ b/crates/assists/src/utils/insert_use.rs
@@ -15,7 +15,7 @@ use syntax::{
15}; 15};
16use test_utils::mark; 16use test_utils::mark;
17 17
18#[derive(Debug)] 18#[derive(Debug, Clone)]
19pub enum ImportScope { 19pub enum ImportScope {
20 File(ast::SourceFile), 20 File(ast::SourceFile),
21 Module(ast::ItemList), 21 Module(ast::ItemList),
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index 75dbb1a23..9b7d6c580 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -90,7 +90,7 @@ impl Completions {
90 Some(it) => it, 90 Some(it) => it,
91 None => return, 91 None => return,
92 }; 92 };
93 if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) { 93 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) {
94 self.add(item); 94 self.add(item);
95 } 95 }
96 } 96 }
@@ -101,7 +101,7 @@ impl Completions {
101 func: hir::Function, 101 func: hir::Function,
102 local_name: Option<String>, 102 local_name: Option<String>,
103 ) { 103 ) {
104 let item = render_fn(RenderContext::new(ctx), local_name, func); 104 let item = render_fn(RenderContext::new(ctx), None, local_name, func);
105 self.add(item) 105 self.add(item)
106 } 106 }
107 107
@@ -123,7 +123,7 @@ impl Completions {
123 variant: hir::EnumVariant, 123 variant: hir::EnumVariant,
124 path: ModPath, 124 path: ModPath,
125 ) { 125 ) {
126 let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path)); 126 let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path));
127 self.add(item); 127 self.add(item);
128 } 128 }
129 129
@@ -133,7 +133,7 @@ impl Completions {
133 variant: hir::EnumVariant, 133 variant: hir::EnumVariant,
134 local_name: Option<String>, 134 local_name: Option<String>,
135 ) { 135 ) {
136 let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None); 136 let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None);
137 self.add(item); 137 self.add(item);
138 } 138 }
139} 139}
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 4f8ec1e67..86c143b63 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -1,14 +1,14 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; 3use assists::utils::ImportScope;
4use either::Either; 4use either::Either;
5use hir::{Adt, ModuleDef, ScopeDef, Type}; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
6use ide_db::imports_locator; 6use ide_db::imports_locator;
7use syntax::{algo, AstNode}; 7use syntax::AstNode;
8use test_utils::mark; 8use test_utils::mark;
9 9
10use crate::{ 10use crate::{
11 render::{render_resolution, RenderContext}, 11 render::{render_resolution_with_import, RenderContext},
12 CompletionContext, Completions, 12 CompletionContext, Completions,
13}; 13};
14 14
@@ -95,35 +95,13 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
95 )), 95 )),
96 }) 96 })
97 .filter(|(mod_path, _)| mod_path.len() > 1) 97 .filter(|(mod_path, _)| mod_path.len() > 1)
98 .filter_map(|(mod_path, definition)| { 98 .filter_map(|(import_path, definition)| {
99 let use_to_insert = mod_path_to_ast(&mod_path); 99 render_resolution_with_import(
100 let mut mod_path_without_last_segment = mod_path; 100 RenderContext::new(ctx),
101 let name_after_import = mod_path_without_last_segment.segments.pop()?.to_string(); 101 import_path.clone(),
102 102 import_scope.clone(),
103 let resolution_with_missing_import = 103 ctx.config.merge,
104 render_resolution(RenderContext::new(ctx), name_after_import, &definition)?; 104 &definition,
105 let lookup_string = resolution_with_missing_import.lookup().to_owned();
106
107 let mut text_edits =
108 resolution_with_missing_import.text_edit().to_owned().into_builder();
109 let rewriter = insert_use(&import_scope, use_to_insert, ctx.config.merge);
110 let old_ast = rewriter.rewrite_root()?;
111 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
112
113 let qualifier_string = mod_path_without_last_segment.to_string();
114 let qualified_label = if qualifier_string.is_empty() {
115 resolution_with_missing_import.label().to_owned()
116 } else {
117 format!("{}::{}", qualifier_string, resolution_with_missing_import.label())
118 };
119
120 Some(
121 resolution_with_missing_import
122 .into_builder()
123 .text_edit(text_edits.finish())
124 .label(qualified_label)
125 .lookup_by(lookup_string)
126 .build(),
127 ) 105 )
128 }) 106 })
129 .take(20); 107 .take(20);
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 24b9d036a..b13c3f376 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -2,8 +2,9 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, Mutability}; 5use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour};
6use syntax::TextRange; 6use hir::{Documentation, ModPath, Mutability};
7use syntax::{algo, TextRange};
7use text_edit::TextEdit; 8use text_edit::TextEdit;
8 9
9use crate::config::SnippetCap; 10use crate::config::SnippetCap;
@@ -200,25 +201,7 @@ impl CompletionItem {
200 trigger_call_info: None, 201 trigger_call_info: None,
201 score: None, 202 score: None,
202 ref_match: None, 203 ref_match: None,
203 } 204 import_data: None,
204 }
205
206 pub(crate) fn into_builder(self) -> Builder {
207 Builder {
208 source_range: self.source_range,
209 completion_kind: self.completion_kind,
210 label: self.label,
211 insert_text: None,
212 insert_text_format: self.insert_text_format,
213 detail: self.detail,
214 documentation: self.documentation,
215 lookup: self.lookup,
216 kind: self.kind,
217 text_edit: Some(self.text_edit),
218 deprecated: Some(self.deprecated),
219 trigger_call_info: Some(self.trigger_call_info),
220 score: self.score,
221 ref_match: self.ref_match,
222 } 205 }
223 } 206 }
224 207
@@ -278,6 +261,7 @@ impl CompletionItem {
278pub(crate) struct Builder { 261pub(crate) struct Builder {
279 source_range: TextRange, 262 source_range: TextRange,
280 completion_kind: CompletionKind, 263 completion_kind: CompletionKind,
264 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
281 label: String, 265 label: String,
282 insert_text: Option<String>, 266 insert_text: Option<String>,
283 insert_text_format: InsertTextFormat, 267 insert_text_format: InsertTextFormat,
@@ -294,23 +278,50 @@ pub(crate) struct Builder {
294 278
295impl Builder { 279impl Builder {
296 pub(crate) fn build(self) -> CompletionItem { 280 pub(crate) fn build(self) -> CompletionItem {
297 let label = self.label; 281 let mut label = self.label;
298 let text_edit = match self.text_edit { 282 let mut lookup = self.lookup;
283 let mut insert_text = self.insert_text;
284 let mut text_edits = TextEdit::builder();
285
286 if let Some((import_path, import_scope, merge_behaviour)) = self.import_data {
287 let import = mod_path_to_ast(&import_path);
288 let mut import_path_without_last_segment = import_path;
289 let _ = import_path_without_last_segment.segments.pop();
290
291 if !import_path_without_last_segment.segments.is_empty() {
292 if lookup.is_none() {
293 lookup = Some(label.clone());
294 }
295 if insert_text.is_none() {
296 insert_text = Some(label.clone());
297 }
298 label = format!("{}::{}", import_path_without_last_segment, label);
299 }
300
301 let rewriter = insert_use(&import_scope, import, merge_behaviour);
302 if let Some(old_ast) = rewriter.rewrite_root() {
303 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
304 }
305 }
306
307 let original_edit = match self.text_edit {
299 Some(it) => it, 308 Some(it) => it,
300 None => TextEdit::replace( 309 None => {
301 self.source_range, 310 TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
302 self.insert_text.unwrap_or_else(|| label.clone()), 311 }
303 ),
304 }; 312 };
305 313
314 let mut resulting_edit = text_edits.finish();
315 resulting_edit.union(original_edit).expect("Failed to unite text edits");
316
306 CompletionItem { 317 CompletionItem {
307 source_range: self.source_range, 318 source_range: self.source_range,
308 label, 319 label,
309 insert_text_format: self.insert_text_format, 320 insert_text_format: self.insert_text_format,
310 text_edit, 321 text_edit: resulting_edit,
311 detail: self.detail, 322 detail: self.detail,
312 documentation: self.documentation, 323 documentation: self.documentation,
313 lookup: self.lookup, 324 lookup,
314 kind: self.kind, 325 kind: self.kind,
315 completion_kind: self.completion_kind, 326 completion_kind: self.completion_kind,
316 deprecated: self.deprecated.unwrap_or(false), 327 deprecated: self.deprecated.unwrap_or(false),
@@ -379,6 +390,13 @@ impl Builder {
379 self.trigger_call_info = Some(true); 390 self.trigger_call_info = Some(true);
380 self 391 self
381 } 392 }
393 pub(crate) fn import_data(
394 mut self,
395 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
396 ) -> Builder {
397 self.import_data = import_data;
398 self
399 }
382 pub(crate) fn set_ref_match( 400 pub(crate) fn set_ref_match(
383 mut self, 401 mut self,
384 ref_match: Option<(Mutability, CompletionScore)>, 402 ref_match: Option<(Mutability, CompletionScore)>,
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 5a4353846..e892d4de8 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -9,7 +9,8 @@ pub(crate) mod type_alias;
9 9
10mod builder_ext; 10mod builder_ext;
11 11
12use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; 12use assists::utils::{ImportScope, MergeBehaviour};
13use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
13use ide_db::RootDatabase; 14use ide_db::RootDatabase;
14use syntax::TextRange; 15use syntax::TextRange;
15use test_utils::mark; 16use test_utils::mark;
@@ -42,7 +43,22 @@ pub(crate) fn render_resolution<'a>(
42 local_name: String, 43 local_name: String,
43 resolution: &ScopeDef, 44 resolution: &ScopeDef,
44) -> Option<CompletionItem> { 45) -> Option<CompletionItem> {
45 Render::new(ctx).render_resolution(local_name, resolution) 46 Render::new(ctx).render_resolution(local_name, None, resolution)
47}
48
49pub(crate) fn render_resolution_with_import<'a>(
50 ctx: RenderContext<'a>,
51 import: ModPath,
52 import_scope: ImportScope,
53 merge_behaviour: Option<MergeBehaviour>,
54 resolution: &ScopeDef,
55) -> Option<CompletionItem> {
56 let local_name = import.segments.last()?.to_string();
57 Render::new(ctx).render_resolution(
58 local_name,
59 Some((import, import_scope, merge_behaviour)),
60 resolution,
61 )
46} 62}
47 63
48/// Interface for data and methods required for items rendering. 64/// Interface for data and methods required for items rendering.
@@ -131,6 +147,7 @@ impl<'a> Render<'a> {
131 fn render_resolution( 147 fn render_resolution(
132 self, 148 self,
133 local_name: String, 149 local_name: String,
150 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
134 resolution: &ScopeDef, 151 resolution: &ScopeDef,
135 ) -> Option<CompletionItem> { 152 ) -> Option<CompletionItem> {
136 use hir::ModuleDef::*; 153 use hir::ModuleDef::*;
@@ -142,15 +159,15 @@ impl<'a> Render<'a> {
142 159
143 let kind = match resolution { 160 let kind = match resolution {
144 ScopeDef::ModuleDef(Function(func)) => { 161 ScopeDef::ModuleDef(Function(func)) => {
145 let item = render_fn(self.ctx, Some(local_name), *func); 162 let item = render_fn(self.ctx, import_data, Some(local_name), *func);
146 return Some(item); 163 return Some(item);
147 } 164 }
148 ScopeDef::ModuleDef(EnumVariant(var)) => { 165 ScopeDef::ModuleDef(EnumVariant(var)) => {
149 let item = render_enum_variant(self.ctx, Some(local_name), *var, None); 166 let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None);
150 return Some(item); 167 return Some(item);
151 } 168 }
152 ScopeDef::MacroDef(mac) => { 169 ScopeDef::MacroDef(mac) => {
153 let item = render_macro(self.ctx, local_name, *mac); 170 let item = render_macro(self.ctx, import_data, local_name, *mac);
154 return item; 171 return item;
155 } 172 }
156 173
@@ -175,6 +192,7 @@ impl<'a> Render<'a> {
175 local_name, 192 local_name,
176 ) 193 )
177 .kind(CompletionItemKind::UnresolvedReference) 194 .kind(CompletionItemKind::UnresolvedReference)
195 .import_data(import_data)
178 .build(); 196 .build();
179 return Some(item); 197 return Some(item);
180 } 198 }
@@ -227,7 +245,12 @@ impl<'a> Render<'a> {
227 } 245 }
228 } 246 }
229 247
230 let item = item.kind(kind).set_documentation(docs).set_ref_match(ref_match).build(); 248 let item = item
249 .kind(kind)
250 .import_data(import_data)
251 .set_documentation(docs)
252 .set_ref_match(ref_match)
253 .build();
231 Some(item) 254 Some(item)
232 } 255 }
233 256
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index fd412ed0e..6070e9b1d 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -1,5 +1,6 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use assists::utils::{ImportScope, MergeBehaviour};
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 4use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use itertools::Itertools; 5use itertools::Itertools;
5use test_utils::mark; 6use test_utils::mark;
@@ -11,11 +12,12 @@ use crate::{
11 12
12pub(crate) fn render_enum_variant<'a>( 13pub(crate) fn render_enum_variant<'a>(
13 ctx: RenderContext<'a>, 14 ctx: RenderContext<'a>,
15 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
14 local_name: Option<String>, 16 local_name: Option<String>,
15 variant: hir::EnumVariant, 17 variant: hir::EnumVariant,
16 path: Option<ModPath>, 18 path: Option<ModPath>,
17) -> CompletionItem { 19) -> CompletionItem {
18 EnumVariantRender::new(ctx, local_name, variant, path).render() 20 EnumVariantRender::new(ctx, local_name, variant, path).render(import_data)
19} 21}
20 22
21#[derive(Debug)] 23#[derive(Debug)]
@@ -60,7 +62,10 @@ impl<'a> EnumVariantRender<'a> {
60 } 62 }
61 } 63 }
62 64
63 fn render(self) -> CompletionItem { 65 fn render(
66 self,
67 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
68 ) -> CompletionItem {
64 let mut builder = CompletionItem::new( 69 let mut builder = CompletionItem::new(
65 CompletionKind::Reference, 70 CompletionKind::Reference,
66 self.ctx.source_range(), 71 self.ctx.source_range(),
@@ -69,6 +74,7 @@ impl<'a> EnumVariantRender<'a> {
69 .kind(CompletionItemKind::EnumVariant) 74 .kind(CompletionItemKind::EnumVariant)
70 .set_documentation(self.variant.docs(self.ctx.db())) 75 .set_documentation(self.variant.docs(self.ctx.db()))
71 .set_deprecated(self.ctx.is_deprecated(self.variant)) 76 .set_deprecated(self.ctx.is_deprecated(self.variant))
77 .import_data(import_data)
72 .detail(self.detail()); 78 .detail(self.detail());
73 79
74 if self.variant_kind == StructKind::Tuple { 80 if self.variant_kind == StructKind::Tuple {
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 4fa6eafd7..9dd5cd18c 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -1,6 +1,7 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, Type}; 3use assists::utils::{ImportScope, MergeBehaviour};
4use hir::{HasSource, ModPath, Type};
4use syntax::{ast::Fn, display::function_declaration}; 5use syntax::{ast::Fn, display::function_declaration};
5 6
6use crate::{ 7use crate::{
@@ -10,10 +11,11 @@ use crate::{
10 11
11pub(crate) fn render_fn<'a>( 12pub(crate) fn render_fn<'a>(
12 ctx: RenderContext<'a>, 13 ctx: RenderContext<'a>,
14 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
13 local_name: Option<String>, 15 local_name: Option<String>,
14 fn_: hir::Function, 16 fn_: hir::Function,
15) -> CompletionItem { 17) -> CompletionItem {
16 FunctionRender::new(ctx, local_name, fn_).render() 18 FunctionRender::new(ctx, local_name, fn_).render(import_data)
17} 19}
18 20
19#[derive(Debug)] 21#[derive(Debug)]
@@ -36,7 +38,10 @@ impl<'a> FunctionRender<'a> {
36 FunctionRender { ctx, name, fn_, ast_node } 38 FunctionRender { ctx, name, fn_, ast_node }
37 } 39 }
38 40
39 fn render(self) -> CompletionItem { 41 fn render(
42 self,
43 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
44 ) -> CompletionItem {
40 let params = self.params(); 45 let params = self.params();
41 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) 46 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
42 .kind(self.kind()) 47 .kind(self.kind())
@@ -44,6 +49,7 @@ impl<'a> FunctionRender<'a> {
44 .set_deprecated(self.ctx.is_deprecated(self.fn_)) 49 .set_deprecated(self.ctx.is_deprecated(self.fn_))
45 .detail(self.detail()) 50 .detail(self.detail())
46 .add_call_parens(self.ctx.completion, self.name, params) 51 .add_call_parens(self.ctx.completion, self.name, params)
52 .import_data(import_data)
47 .build() 53 .build()
48 } 54 }
49 55
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index 96be59cc3..fead59e41 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -1,6 +1,7 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use assists::utils::{ImportScope, MergeBehaviour};
4use hir::{Documentation, HasSource, ModPath};
4use syntax::display::macro_label; 5use syntax::display::macro_label;
5use test_utils::mark; 6use test_utils::mark;
6 7
@@ -11,10 +12,11 @@ use crate::{
11 12
12pub(crate) fn render_macro<'a>( 13pub(crate) fn render_macro<'a>(
13 ctx: RenderContext<'a>, 14 ctx: RenderContext<'a>,
15 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
14 name: String, 16 name: String,
15 macro_: hir::MacroDef, 17 macro_: hir::MacroDef,
16) -> Option<CompletionItem> { 18) -> Option<CompletionItem> {
17 MacroRender::new(ctx, name, macro_).render() 19 MacroRender::new(ctx, name, macro_).render(import_data)
18} 20}
19 21
20#[derive(Debug)] 22#[derive(Debug)]
@@ -36,7 +38,10 @@ impl<'a> MacroRender<'a> {
36 MacroRender { ctx, name, macro_, docs, bra, ket } 38 MacroRender { ctx, name, macro_, docs, bra, ket }
37 } 39 }
38 40
39 fn render(&self) -> Option<CompletionItem> { 41 fn render(
42 &self,
43 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
44 ) -> Option<CompletionItem> {
40 // FIXME: Currently proc-macro do not have ast-node, 45 // FIXME: Currently proc-macro do not have ast-node,
41 // such that it does not have source 46 // such that it does not have source
42 if self.macro_.is_proc_macro() { 47 if self.macro_.is_proc_macro() {
@@ -48,6 +53,7 @@ impl<'a> MacroRender<'a> {
48 .kind(CompletionItemKind::Macro) 53 .kind(CompletionItemKind::Macro)
49 .set_documentation(self.docs.clone()) 54 .set_documentation(self.docs.clone())
50 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 55 .set_deprecated(self.ctx.is_deprecated(self.macro_))
56 .import_data(import_data)
51 .detail(self.detail()); 57 .detail(self.detail());
52 58
53 let needs_bang = self.needs_bang(); 59 let needs_bang = self.needs_bang();
diff --git a/crates/text_edit/src/lib.rs b/crates/text_edit/src/lib.rs
index 9eef7a890..eb3c8caa2 100644
--- a/crates/text_edit/src/lib.rs
+++ b/crates/text_edit/src/lib.rs
@@ -48,10 +48,6 @@ impl TextEdit {
48 TextEditBuilder::default() 48 TextEditBuilder::default()
49 } 49 }
50 50
51 pub fn into_builder(self) -> TextEditBuilder {
52 TextEditBuilder { indels: self.indels }
53 }
54
55 pub fn insert(offset: TextSize, text: String) -> TextEdit { 51 pub fn insert(offset: TextSize, text: String) -> TextEdit {
56 let mut builder = TextEdit::builder(); 52 let mut builder = TextEdit::builder();
57 builder.insert(offset, text); 53 builder.insert(offset, text);