aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-03-28 10:01:25 +0000
committerAleksey Kladov <[email protected]>2020-03-28 10:01:25 +0000
commitb764c38436fcb9426eb7da3be4f5fbcd63b316f5 (patch)
treea599f1ffff953040a0c2bb635b33b0f6a57e5e59 /crates
parenta1fea0d34ee8f3436aefd87d4c133a7ff50ffbb0 (diff)
Start stdx
This crate will hold everything to small to be worth publishing
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/Cargo.toml4
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs14
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs9
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs39
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs4
-rw-r--r--crates/ra_ide/Cargo.toml4
-rw-r--r--crates/ra_ide/src/completion/presentation.rs45
-rw-r--r--crates/ra_ide/src/diagnostics.rs18
-rw-r--r--crates/ra_ide/src/display/function_signature.rs18
-rw-r--r--crates/ra_ide/src/display/short_label.rs4
-rw-r--r--crates/stdx/Cargo.toml11
-rw-r--r--crates/stdx/src/lib.rs75
12 files changed, 157 insertions, 88 deletions
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index a87f4052a..3bcf58ba4 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -8,12 +8,12 @@ authors = ["rust-analyzer developers"]
8doctest = false 8doctest = false
9 9
10[dependencies] 10[dependencies]
11format-buf = "1.0.0"
12join_to_string = "0.1.3"
13rustc-hash = "1.1.0" 11rustc-hash = "1.1.0"
14itertools = "0.9.0" 12itertools = "0.9.0"
15either = "1.5.3" 13either = "1.5.3"
16 14
15stdx = { path = "../stdx" }
16
17ra_syntax = { path = "../ra_syntax" } 17ra_syntax = { path = "../ra_syntax" }
18ra_text_edit = { path = "../ra_text_edit" } 18ra_text_edit = { path = "../ra_text_edit" }
19ra_fmt = { path = "../ra_fmt" } 19ra_fmt = { path = "../ra_fmt" }
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index dd2bed25a..15f9b216b 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -1,17 +1,13 @@
1//! FIXME: write short doc here
2
3use join_to_string::join;
4use ra_syntax::{ 1use ra_syntax::{
5 ast::{self, AstNode}, 2 ast::{self, AstNode},
6 Direction, SmolStr, 3 Direction, SmolStr,
7 SyntaxKind::{IDENT, WHITESPACE}, 4 SyntaxKind::{IDENT, WHITESPACE},
8 TextRange, TextUnit, 5 TextRange, TextUnit,
9}; 6};
7use stdx::SepBy;
10 8
11use crate::{Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
12 10
13const DERIVE_TRAIT: &str = "derive";
14
15// Assist: add_custom_impl 11// Assist: add_custom_impl
16// 12//
17// Adds impl block for derived trait. 13// Adds impl block for derived trait.
@@ -38,7 +34,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
38 .descendants_with_tokens() 34 .descendants_with_tokens()
39 .filter(|t| t.kind() == IDENT) 35 .filter(|t| t.kind() == IDENT)
40 .find_map(|i| i.into_token()) 36 .find_map(|i| i.into_token())
41 .filter(|t| *t.text() == DERIVE_TRAIT)? 37 .filter(|t| *t.text() == "derive")?
42 .text() 38 .text()
43 .clone(); 39 .clone();
44 40
@@ -63,8 +59,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
63 .filter(|t| t != trait_token.text()) 59 .filter(|t| t != trait_token.text())
64 .collect::<Vec<SmolStr>>(); 60 .collect::<Vec<SmolStr>>();
65 let has_more_derives = !new_attr_input.is_empty(); 61 let has_more_derives = !new_attr_input.is_empty();
66 let new_attr_input = 62 let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
67 join(new_attr_input.iter()).separator(", ").surround_with("(", ")").to_string();
68 let new_attr_input_len = new_attr_input.len(); 63 let new_attr_input_len = new_attr_input.len();
69 64
70 let mut buf = String::new(); 65 let mut buf = String::new();
@@ -100,9 +95,10 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
100 95
101#[cfg(test)] 96#[cfg(test)]
102mod tests { 97mod tests {
103 use super::*;
104 use crate::helpers::{check_assist, check_assist_not_applicable}; 98 use crate::helpers::{check_assist, check_assist_not_applicable};
105 99
100 use super::*;
101
106 #[test] 102 #[test]
107 fn add_custom_impl_for_unique_input() { 103 fn add_custom_impl_for_unique_input() {
108 check_assist( 104 check_assist(
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
index afae7d385..6622eadb2 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -1,9 +1,8 @@
1use format_buf::format;
2use join_to_string::join;
3use ra_syntax::{ 1use ra_syntax::{
4 ast::{self, AstNode, NameOwner, TypeParamsOwner}, 2 ast::{self, AstNode, NameOwner, TypeParamsOwner},
5 TextUnit, 3 TextUnit,
6}; 4};
5use stdx::{format_to, SepBy};
7 6
8use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
9 8
@@ -36,7 +35,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
36 let mut buf = String::new(); 35 let mut buf = String::new();
37 buf.push_str("\n\nimpl"); 36 buf.push_str("\n\nimpl");
38 if let Some(type_params) = &type_params { 37 if let Some(type_params) = &type_params {
39 format!(buf, "{}", type_params.syntax()); 38 format_to!(buf, "{}", type_params.syntax());
40 } 39 }
41 buf.push_str(" "); 40 buf.push_str(" ");
42 buf.push_str(name.text().as_str()); 41 buf.push_str(name.text().as_str());
@@ -47,7 +46,9 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
47 .map(|it| it.text().clone()); 46 .map(|it| it.text().clone());
48 let type_params = 47 let type_params =
49 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 48 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
50 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); 49
50 let generic_params = lifetime_params.chain(type_params).sep_by(", ");
51 format_to!(buf, "<{}>", generic_params)
51 } 52 }
52 buf.push_str(" {\n"); 53 buf.push_str(" {\n");
53 edit.set_cursor(start_offset + TextUnit::of_str(&buf)); 54 edit.set_cursor(start_offset + TextUnit::of_str(&buf));
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 729a223e0..240b19fa3 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -1,14 +1,11 @@
1use std::fmt::Write;
2
3use format_buf::format;
4use hir::Adt; 1use hir::Adt;
5use join_to_string::join;
6use ra_syntax::{ 2use ra_syntax::{
7 ast::{ 3 ast::{
8 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, 4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
9 }, 5 },
10 TextUnit, T, 6 TextUnit, T,
11}; 7};
8use stdx::{format_to, SepBy};
12 9
13use crate::{Assist, AssistCtx, AssistId}; 10use crate::{Assist, AssistCtx, AssistId};
14 11
@@ -53,24 +50,22 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
53 buf.push('\n'); 50 buf.push('\n');
54 } 51 }
55 52
56 let vis = strukt.visibility().map(|v| format!("{} ", v.syntax())); 53 let vis = strukt.visibility().map(|v| format!("{} ", v));
57 let vis = vis.as_deref().unwrap_or(""); 54 let vis = vis.as_deref().unwrap_or("");
58 write!(&mut buf, " {}fn new(", vis).unwrap();
59
60 join(field_list.fields().filter_map(|f| {
61 Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
62 }))
63 .separator(", ")
64 .to_buf(&mut buf);
65 55
66 buf.push_str(") -> Self { Self {"); 56 let params = field_list
67 57 .fields()
68 join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text()))) 58 .filter_map(|f| {
69 .separator(", ") 59 Some(format!(
70 .surround_with(" ", " ") 60 "{}: {}",
71 .to_buf(&mut buf); 61 f.name()?.syntax().text(),
62 f.ascribed_type()?.syntax().text()
63 ))
64 })
65 .sep_by(", ");
66 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", ");
72 67
73 buf.push_str("} }"); 68 format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
74 69
75 let (start_offset, end_offset) = impl_def 70 let (start_offset, end_offset) = impl_def
76 .and_then(|impl_def| { 71 .and_then(|impl_def| {
@@ -103,7 +98,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
103 let mut buf = String::with_capacity(code.len()); 98 let mut buf = String::with_capacity(code.len());
104 buf.push_str("\n\nimpl"); 99 buf.push_str("\n\nimpl");
105 if let Some(type_params) = &type_params { 100 if let Some(type_params) = &type_params {
106 format!(buf, "{}", type_params.syntax()); 101 format_to!(buf, "{}", type_params.syntax());
107 } 102 }
108 buf.push_str(" "); 103 buf.push_str(" ");
109 buf.push_str(strukt.name().unwrap().text().as_str()); 104 buf.push_str(strukt.name().unwrap().text().as_str());
@@ -114,10 +109,10 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
114 .map(|it| it.text().clone()); 109 .map(|it| it.text().clone());
115 let type_params = 110 let type_params =
116 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 111 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
117 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); 112 format_to!(buf, "<{}>", lifetime_params.chain(type_params).sep_by(", "))
118 } 113 }
119 114
120 format!(&mut buf, " {{\n{}\n}}\n", code); 115 format_to!(buf, " {{\n{}\n}}\n", code);
121 116
122 buf 117 buf
123} 118}
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index b453c51fb..1edbdc14c 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -1,4 +1,3 @@
1use format_buf::format;
2use ra_syntax::{ 1use ra_syntax::{
3 ast::{self, AstNode}, 2 ast::{self, AstNode},
4 SyntaxKind::{ 3 SyntaxKind::{
@@ -7,6 +6,7 @@ use ra_syntax::{
7 }, 6 },
8 SyntaxNode, TextUnit, 7 SyntaxNode, TextUnit,
9}; 8};
9use stdx::format_to;
10use test_utils::tested_by; 10use test_utils::tested_by;
11 11
12use crate::{Assist, AssistCtx, AssistId}; 12use crate::{Assist, AssistCtx, AssistId};
@@ -52,7 +52,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
52 buf.push_str("let var_name = "); 52 buf.push_str("let var_name = ");
53 TextUnit::of_str("let ") 53 TextUnit::of_str("let ")
54 }; 54 };
55 format!(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());
57 let is_full_stmt = if let Some(expr_stmt) = &full_stmt { 57 let is_full_stmt = if let Some(expr_stmt) = &full_stmt {
58 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) 58 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone())
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index 36eec0e60..b4a29b81b 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -12,14 +12,14 @@ wasm = []
12 12
13[dependencies] 13[dependencies]
14either = "1.5.3" 14either = "1.5.3"
15format-buf = "1.0.0"
16indexmap = "1.3.2" 15indexmap = "1.3.2"
17itertools = "0.9.0" 16itertools = "0.9.0"
18join_to_string = "0.1.3"
19log = "0.4.8" 17log = "0.4.8"
20rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
21rand = { version = "0.7.3", features = ["small_rng"] } 19rand = { version = "0.7.3", features = ["small_rng"] }
22 20
21stdx = { path = "../stdx" }
22
23ra_syntax = { path = "../ra_syntax" } 23ra_syntax = { path = "../ra_syntax" }
24ra_text_edit = { path = "../ra_text_edit" } 24ra_text_edit = { path = "../ra_text_edit" }
25ra_db = { path = "../ra_db" } 25ra_db = { path = "../ra_db" }
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 253848602..60f1b83f3 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1,15 +1,14 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; 3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type};
4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 4use ra_syntax::ast::NameOwner;
5use stdx::SepBy;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10};
11
12use crate::{ 8use crate::{
9 completion::{
10 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
11 },
13 display::{const_label, macro_label, type_label, FunctionSignature}, 12 display::{const_label, macro_label, type_label, FunctionSignature},
14 RootDatabase, 13 RootDatabase,
15}; 14};
@@ -221,13 +220,13 @@ impl Completions {
221 builder = builder.trigger_call_info(); 220 builder = builder.trigger_call_info();
222 let snippet = if ctx.options.add_call_argument_snippets { 221 let snippet = if ctx.options.add_call_argument_snippets {
223 let to_skip = if has_self_param { 1 } else { 0 }; 222 let to_skip = if has_self_param { 1 } else { 0 };
224 let function_params_snippet = join( 223 let function_params_snippet = function_signature
225 function_signature.parameter_names.iter().skip(to_skip).enumerate().map( 224 .parameter_names
226 |(index, param_name)| format!("${{{}:{}}}", index + 1, param_name), 225 .iter()
227 ), 226 .skip(to_skip)
228 ) 227 .enumerate()
229 .separator(", ") 228 .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name))
230 .to_string(); 229 .sep_by(", ");
231 format!("{}({})$0", name, function_params_snippet) 230 format!("{}({})$0", name, function_params_snippet)
232 } else { 231 } else {
233 format!("{}($0)", name) 232 format!("{}($0)", name)
@@ -281,18 +280,16 @@ impl Completions {
281 .into_iter() 280 .into_iter()
282 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); 281 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
283 let detail = match variant.kind(ctx.db) { 282 let detail = match variant.kind(ctx.db) {
284 StructKind::Tuple | StructKind::Unit => { 283 StructKind::Tuple | StructKind::Unit => detail_types
285 join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) 284 .map(|(_, t)| t.display(ctx.db).to_string())
286 .separator(", ") 285 .sep_by(", ")
287 .surround_with("(", ")") 286 .surround_with("(", ")")
288 .to_string() 287 .to_string(),
289 } 288 StructKind::Record => detail_types
290 StructKind::Record => { 289 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))
291 join(detail_types.map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))) 290 .sep_by(", ")
292 .separator(", ") 291 .surround_with("{ ", " }")
293 .surround_with("{ ", " }") 292 .to_string(),
294 .to_string()
295 }
296 }; 293 };
297 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 294 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
298 .kind(CompletionItemKind::EnumVariant) 295 .kind(CompletionItemKind::EnumVariant)
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index a10e642db..c1d7ddaf2 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -200,8 +200,8 @@ fn check_struct_shorthand_initialization(
200#[cfg(test)] 200#[cfg(test)]
201mod tests { 201mod tests {
202 use insta::assert_debug_snapshot; 202 use insta::assert_debug_snapshot;
203 use join_to_string::join;
204 use ra_syntax::SourceFile; 203 use ra_syntax::SourceFile;
204 use stdx::SepBy;
205 use test_utils::assert_eq_text; 205 use test_utils::assert_eq_text;
206 206
207 use crate::mock_analysis::{analysis_and_position, single_file}; 207 use crate::mock_analysis::{analysis_and_position, single_file};
@@ -254,16 +254,12 @@ mod tests {
254 .map(|it| it.len() - it.trim_start().len()) 254 .map(|it| it.len() - it.trim_start().len())
255 .next() 255 .next()
256 .expect("empty fixture"); 256 .expect("empty fixture");
257 let after = join(after.lines().filter_map(|line| { 257 let after = after
258 if line.len() > margin { 258 .lines()
259 Some(&line[margin..]) 259 .filter_map(|line| if line.len() > margin { Some(&line[margin..]) } else { None })
260 } else { 260 .sep_by("\n")
261 None 261 .suffix("\n")
262 } 262 .to_string();
263 }))
264 .separator("\n")
265 .suffix("\n")
266 .to_string();
267 263
268 assert_eq_text!(&after, &actual); 264 assert_eq_text!(&after, &actual);
269 assert!( 265 assert!(
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index ec1bbd5a0..b967a6816 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -1,12 +1,14 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::fmt::{self, Display}; 3use std::{
4 convert::From,
5 fmt::{self, Display},
6};
4 7
5use hir::{Docs, Documentation, HasSource, HirDisplay}; 8use hir::{Docs, Documentation, HasSource, HirDisplay};
6use join_to_string::join;
7use ra_ide_db::RootDatabase; 9use ra_ide_db::RootDatabase;
8use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; 10use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
9use std::convert::From; 11use stdx::SepBy;
10 12
11use crate::display::{generic_parameters, where_predicates}; 13use crate::display::{generic_parameters, where_predicates};
12 14
@@ -227,21 +229,17 @@ impl Display for FunctionSignature {
227 } 229 }
228 230
229 if !self.generic_parameters.is_empty() { 231 if !self.generic_parameters.is_empty() {
230 join(self.generic_parameters.iter()) 232 write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?;
231 .separator(", ")
232 .surround_with("<", ">")
233 .to_fmt(f)?;
234 } 233 }
235 234
236 join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; 235 write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?;
237 236
238 if let Some(t) = &self.ret_type { 237 if let Some(t) = &self.ret_type {
239 write!(f, " -> {}", t)?; 238 write!(f, " -> {}", t)?;
240 } 239 }
241 240
242 if !self.where_predicates.is_empty() { 241 if !self.where_predicates.is_empty() {
243 write!(f, "\nwhere ")?; 242 write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?;
244 join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?;
245 } 243 }
246 244
247 Ok(()) 245 Ok(())
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs
index 9ffc9b980..4b081bf6c 100644
--- a/crates/ra_ide/src/display/short_label.rs
+++ b/crates/ra_ide/src/display/short_label.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use format_buf::format;
4use ra_syntax::ast::{self, AstNode, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 3use ra_syntax::ast::{self, AstNode, NameOwner, TypeAscriptionOwner, VisibilityOwner};
4use stdx::format_to;
5 5
6pub(crate) trait ShortLabel { 6pub(crate) trait ShortLabel {
7 fn short_label(&self) -> Option<String>; 7 fn short_label(&self) -> Option<String>;
@@ -80,7 +80,7 @@ where
80 let mut buf = short_label_from_node(node, prefix)?; 80 let mut buf = short_label_from_node(node, prefix)?;
81 81
82 if let Some(type_ref) = node.ascribed_type() { 82 if let Some(type_ref) = node.ascribed_type() {
83 format!(buf, ": {}", type_ref.syntax()); 83 format_to!(buf, ": {}", type_ref.syntax());
84 } 84 }
85 85
86 Some(buf) 86 Some(buf)
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
new file mode 100644
index 000000000..f9e380c10
--- /dev/null
+++ b/crates/stdx/Cargo.toml
@@ -0,0 +1,11 @@
1[package]
2name = "stdx"
3version = "0.1.0"
4authors = ["rust-analyzer developers"]
5edition = "2018"
6
7[lib]
8doctest = false
9
10[dependencies]
11# Think twice before adding anything here
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
new file mode 100644
index 000000000..a01ca6d4d
--- /dev/null
+++ b/crates/stdx/src/lib.rs
@@ -0,0 +1,75 @@
1//! Missing batteries for standard libraries.
2
3use std::{cell::Cell, fmt};
4
5/// Appends formatted string to a `String`.
6#[macro_export]
7macro_rules! format_to {
8 (&buf:expr) => ();
9 ($buf:expr, $lit:literal $($arg:tt)*) => {
10 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
11 };
12}
13
14pub trait SepBy: Sized {
15 /// Returns an `impl fmt::Display`, which joins elements via a separator.
16 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>;
17}
18
19impl<I> SepBy for I
20where
21 I: Iterator,
22 I::Item: fmt::Display,
23{
24 fn sep_by<'a>(self, sep: &'a std::primitive::str) -> SepByBuilder<'a, Self> {
25 SepByBuilder::new(sep, self)
26 }
27}
28
29pub struct SepByBuilder<'a, I> {
30 sep: &'a str,
31 prefix: &'a str,
32 suffix: &'a str,
33 iter: Cell<Option<I>>,
34}
35
36impl<'a, I> SepByBuilder<'a, I> {
37 fn new(sep: &'a str, iter: I) -> SepByBuilder<'a, I> {
38 SepByBuilder { sep, prefix: "", suffix: "", iter: Cell::new(Some(iter)) }
39 }
40
41 pub fn prefix(mut self, prefix: &'a str) -> Self {
42 self.prefix = prefix;
43 self
44 }
45
46 pub fn suffix(mut self, suffix: &'a str) -> Self {
47 self.suffix = suffix;
48 self
49 }
50
51 /// Set both suffix and prefix.
52 pub fn surround_with(self, prefix: &'a str, suffix: &'a str) -> Self {
53 self.prefix(prefix).suffix(suffix)
54 }
55}
56
57impl<I> fmt::Display for SepByBuilder<'_, I>
58where
59 I: Iterator,
60 I::Item: fmt::Display,
61{
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.write_str(self.prefix)?;
64 let mut first = true;
65 for item in self.iter.take().unwrap() {
66 if !first {
67 f.write_str(self.sep)?;
68 }
69 first = false;
70 fmt::Display::fmt(&item, f)?;
71 }
72 f.write_str(self.suffix)?;
73 Ok(())
74 }
75}