From b764c38436fcb9426eb7da3be4f5fbcd63b316f5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 28 Mar 2020 11:01:25 +0100 Subject: Start stdx This crate will hold everything to small to be worth publishing --- crates/ra_assists/Cargo.toml | 4 +- crates/ra_assists/src/handlers/add_custom_impl.rs | 14 ++-- crates/ra_assists/src/handlers/add_impl.rs | 9 +-- crates/ra_assists/src/handlers/add_new.rs | 39 +++++------ .../ra_assists/src/handlers/introduce_variable.rs | 4 +- crates/ra_ide/Cargo.toml | 4 +- crates/ra_ide/src/completion/presentation.rs | 45 ++++++------- crates/ra_ide/src/diagnostics.rs | 18 ++---- crates/ra_ide/src/display/function_signature.rs | 18 +++--- crates/ra_ide/src/display/short_label.rs | 4 +- crates/stdx/Cargo.toml | 11 ++++ crates/stdx/src/lib.rs | 75 ++++++++++++++++++++++ 12 files changed, 157 insertions(+), 88 deletions(-) create mode 100644 crates/stdx/Cargo.toml create mode 100644 crates/stdx/src/lib.rs (limited to 'crates') 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"] doctest = false [dependencies] -format-buf = "1.0.0" -join_to_string = "0.1.3" rustc-hash = "1.1.0" itertools = "0.9.0" either = "1.5.3" +stdx = { path = "../stdx" } + ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } ra_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 @@ -//! FIXME: write short doc here - -use join_to_string::join; use ra_syntax::{ ast::{self, AstNode}, Direction, SmolStr, SyntaxKind::{IDENT, WHITESPACE}, TextRange, TextUnit, }; +use stdx::SepBy; use crate::{Assist, AssistCtx, AssistId}; -const DERIVE_TRAIT: &str = "derive"; - // Assist: add_custom_impl // // Adds impl block for derived trait. @@ -38,7 +34,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option { .descendants_with_tokens() .filter(|t| t.kind() == IDENT) .find_map(|i| i.into_token()) - .filter(|t| *t.text() == DERIVE_TRAIT)? + .filter(|t| *t.text() == "derive")? .text() .clone(); @@ -63,8 +59,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option { .filter(|t| t != trait_token.text()) .collect::>(); let has_more_derives = !new_attr_input.is_empty(); - let new_attr_input = - join(new_attr_input.iter()).separator(", ").surround_with("(", ")").to_string(); + let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); let new_attr_input_len = new_attr_input.len(); let mut buf = String::new(); @@ -100,9 +95,10 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option { #[cfg(test)] mod tests { - use super::*; use crate::helpers::{check_assist, check_assist_not_applicable}; + use super::*; + #[test] fn add_custom_impl_for_unique_input() { 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 @@ -use format_buf::format; -use join_to_string::join; use ra_syntax::{ ast::{self, AstNode, NameOwner, TypeParamsOwner}, TextUnit, }; +use stdx::{format_to, SepBy}; use crate::{Assist, AssistCtx, AssistId}; @@ -36,7 +35,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option { let mut buf = String::new(); buf.push_str("\n\nimpl"); if let Some(type_params) = &type_params { - format!(buf, "{}", type_params.syntax()); + format_to!(buf, "{}", type_params.syntax()); } buf.push_str(" "); buf.push_str(name.text().as_str()); @@ -47,7 +46,9 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option { .map(|it| it.text().clone()); let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); - join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); + + let generic_params = lifetime_params.chain(type_params).sep_by(", "); + format_to!(buf, "<{}>", generic_params) } buf.push_str(" {\n"); 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 @@ -use std::fmt::Write; - -use format_buf::format; use hir::Adt; -use join_to_string::join; use ra_syntax::{ ast::{ self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, }, TextUnit, T, }; +use stdx::{format_to, SepBy}; use crate::{Assist, AssistCtx, AssistId}; @@ -53,24 +50,22 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option { buf.push('\n'); } - let vis = strukt.visibility().map(|v| format!("{} ", v.syntax())); + let vis = strukt.visibility().map(|v| format!("{} ", v)); let vis = vis.as_deref().unwrap_or(""); - write!(&mut buf, " {}fn new(", vis).unwrap(); - - join(field_list.fields().filter_map(|f| { - Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text())) - })) - .separator(", ") - .to_buf(&mut buf); - buf.push_str(") -> Self { Self {"); - - join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text()))) - .separator(", ") - .surround_with(" ", " ") - .to_buf(&mut buf); + let params = field_list + .fields() + .filter_map(|f| { + Some(format!( + "{}: {}", + f.name()?.syntax().text(), + f.ascribed_type()?.syntax().text() + )) + }) + .sep_by(", "); + let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); - buf.push_str("} }"); + format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); let (start_offset, end_offset) = impl_def .and_then(|impl_def| { @@ -103,7 +98,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { let mut buf = String::with_capacity(code.len()); buf.push_str("\n\nimpl"); if let Some(type_params) = &type_params { - format!(buf, "{}", type_params.syntax()); + format_to!(buf, "{}", type_params.syntax()); } buf.push_str(" "); buf.push_str(strukt.name().unwrap().text().as_str()); @@ -114,10 +109,10 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { .map(|it| it.text().clone()); let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); - join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); + format_to!(buf, "<{}>", lifetime_params.chain(type_params).sep_by(", ")) } - format!(&mut buf, " {{\n{}\n}}\n", code); + format_to!(buf, " {{\n{}\n}}\n", code); buf } 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 @@ -use format_buf::format; use ra_syntax::{ ast::{self, AstNode}, SyntaxKind::{ @@ -7,6 +6,7 @@ use ra_syntax::{ }, SyntaxNode, TextUnit, }; +use stdx::format_to; use test_utils::tested_by; use crate::{Assist, AssistCtx, AssistId}; @@ -52,7 +52,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option { buf.push_str("let var_name = "); TextUnit::of_str("let ") }; - format!(buf, "{}", expr.syntax()); + format_to!(buf, "{}", expr.syntax()); let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); let is_full_stmt = if let Some(expr_stmt) = &full_stmt { 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 = [] [dependencies] either = "1.5.3" -format-buf = "1.0.0" indexmap = "1.3.2" itertools = "0.9.0" -join_to_string = "0.1.3" log = "0.4.8" rustc-hash = "1.1.0" rand = { version = "0.7.3", features = ["small_rng"] } +stdx = { path = "../stdx" } + ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } ra_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 @@ //! This modules takes care of rendering various definitions as completion items. use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; -use join_to_string::join; use ra_syntax::ast::NameOwner; +use stdx::SepBy; use test_utils::tested_by; -use crate::completion::{ - CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, -}; - use crate::{ + completion::{ + CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, + }, display::{const_label, macro_label, type_label, FunctionSignature}, RootDatabase, }; @@ -221,13 +220,13 @@ impl Completions { builder = builder.trigger_call_info(); let snippet = if ctx.options.add_call_argument_snippets { let to_skip = if has_self_param { 1 } else { 0 }; - let function_params_snippet = join( - function_signature.parameter_names.iter().skip(to_skip).enumerate().map( - |(index, param_name)| format!("${{{}:{}}}", index + 1, param_name), - ), - ) - .separator(", ") - .to_string(); + let function_params_snippet = function_signature + .parameter_names + .iter() + .skip(to_skip) + .enumerate() + .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name)) + .sep_by(", "); format!("{}({})$0", name, function_params_snippet) } else { format!("{}($0)", name) @@ -281,18 +280,16 @@ impl Completions { .into_iter() .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); let detail = match variant.kind(ctx.db) { - StructKind::Tuple | StructKind::Unit => { - join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) - .separator(", ") - .surround_with("(", ")") - .to_string() - } - StructKind::Record => { - join(detail_types.map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))) - .separator(", ") - .surround_with("{ ", " }") - .to_string() - } + StructKind::Tuple | StructKind::Unit => detail_types + .map(|(_, t)| t.display(ctx.db).to_string()) + .sep_by(", ") + .surround_with("(", ")") + .to_string(), + StructKind::Record => detail_types + .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())) + .sep_by(", ") + .surround_with("{ ", " }") + .to_string(), }; CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) .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( #[cfg(test)] mod tests { use insta::assert_debug_snapshot; - use join_to_string::join; use ra_syntax::SourceFile; + use stdx::SepBy; use test_utils::assert_eq_text; use crate::mock_analysis::{analysis_and_position, single_file}; @@ -254,16 +254,12 @@ mod tests { .map(|it| it.len() - it.trim_start().len()) .next() .expect("empty fixture"); - let after = join(after.lines().filter_map(|line| { - if line.len() > margin { - Some(&line[margin..]) - } else { - None - } - })) - .separator("\n") - .suffix("\n") - .to_string(); + let after = after + .lines() + .filter_map(|line| if line.len() > margin { Some(&line[margin..]) } else { None }) + .sep_by("\n") + .suffix("\n") + .to_string(); assert_eq_text!(&after, &actual); 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 @@ //! FIXME: write short doc here -use std::fmt::{self, Display}; +use std::{ + convert::From, + fmt::{self, Display}, +}; use hir::{Docs, Documentation, HasSource, HirDisplay}; -use join_to_string::join; use ra_ide_db::RootDatabase; use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; -use std::convert::From; +use stdx::SepBy; use crate::display::{generic_parameters, where_predicates}; @@ -227,21 +229,17 @@ impl Display for FunctionSignature { } if !self.generic_parameters.is_empty() { - join(self.generic_parameters.iter()) - .separator(", ") - .surround_with("<", ">") - .to_fmt(f)?; + write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?; } - join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; + write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?; if let Some(t) = &self.ret_type { write!(f, " -> {}", t)?; } if !self.where_predicates.is_empty() { - write!(f, "\nwhere ")?; - join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; + write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?; } 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 @@ //! FIXME: write short doc here -use format_buf::format; use ra_syntax::ast::{self, AstNode, NameOwner, TypeAscriptionOwner, VisibilityOwner}; +use stdx::format_to; pub(crate) trait ShortLabel { fn short_label(&self) -> Option; @@ -80,7 +80,7 @@ where let mut buf = short_label_from_node(node, prefix)?; if let Some(type_ref) = node.ascribed_type() { - format!(buf, ": {}", type_ref.syntax()); + format_to!(buf, ": {}", type_ref.syntax()); } 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 @@ +[package] +name = "stdx" +version = "0.1.0" +authors = ["rust-analyzer developers"] +edition = "2018" + +[lib] +doctest = false + +[dependencies] +# 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 @@ +//! Missing batteries for standard libraries. + +use std::{cell::Cell, fmt}; + +/// Appends formatted string to a `String`. +#[macro_export] +macro_rules! format_to { + (&buf:expr) => (); + ($buf:expr, $lit:literal $($arg:tt)*) => { + { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); } + }; +} + +pub trait SepBy: Sized { + /// Returns an `impl fmt::Display`, which joins elements via a separator. + fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>; +} + +impl SepBy for I +where + I: Iterator, + I::Item: fmt::Display, +{ + fn sep_by<'a>(self, sep: &'a std::primitive::str) -> SepByBuilder<'a, Self> { + SepByBuilder::new(sep, self) + } +} + +pub struct SepByBuilder<'a, I> { + sep: &'a str, + prefix: &'a str, + suffix: &'a str, + iter: Cell>, +} + +impl<'a, I> SepByBuilder<'a, I> { + fn new(sep: &'a str, iter: I) -> SepByBuilder<'a, I> { + SepByBuilder { sep, prefix: "", suffix: "", iter: Cell::new(Some(iter)) } + } + + pub fn prefix(mut self, prefix: &'a str) -> Self { + self.prefix = prefix; + self + } + + pub fn suffix(mut self, suffix: &'a str) -> Self { + self.suffix = suffix; + self + } + + /// Set both suffix and prefix. + pub fn surround_with(self, prefix: &'a str, suffix: &'a str) -> Self { + self.prefix(prefix).suffix(suffix) + } +} + +impl fmt::Display for SepByBuilder<'_, I> +where + I: Iterator, + I::Item: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.prefix)?; + let mut first = true; + for item in self.iter.take().unwrap() { + if !first { + f.write_str(self.sep)?; + } + first = false; + fmt::Display::fmt(&item, f)?; + } + f.write_str(self.suffix)?; + Ok(()) + } +} -- cgit v1.2.3