Merge #3753
3753: Introduce stdx crate r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
c30425dc96
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -353,12 +353,6 @@ version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
|
||||
[[package]]
|
||||
name = "format-buf"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7aea5a5909a74969507051a3b17adc84737e31a5f910559892aedce026f4d53"
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.1.0"
|
||||
@ -573,12 +567,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f52a11f73b88fab829a0e4d9e13ea5982c7ac457c72eb3541d82a4afdfce4ff"
|
||||
|
||||
[[package]]
|
||||
name = "join_to_string"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dc7a5290e8c2606ce2be49f456d50f69173cb96d1541e4f66e34ac8b331a98f"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
@ -885,9 +873,7 @@ name = "ra_assists"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"format-buf",
|
||||
"itertools 0.9.0",
|
||||
"join_to_string",
|
||||
"ra_db",
|
||||
"ra_fmt",
|
||||
"ra_hir",
|
||||
@ -896,6 +882,7 @@ dependencies = [
|
||||
"ra_syntax",
|
||||
"ra_text_edit",
|
||||
"rustc-hash",
|
||||
"stdx",
|
||||
"test_utils",
|
||||
]
|
||||
|
||||
@ -979,6 +966,7 @@ dependencies = [
|
||||
"ra_syntax",
|
||||
"ra_tt",
|
||||
"rustc-hash",
|
||||
"stdx",
|
||||
"test_utils",
|
||||
]
|
||||
|
||||
@ -1015,6 +1003,7 @@ dependencies = [
|
||||
"ra_prof",
|
||||
"ra_syntax",
|
||||
"rustc-hash",
|
||||
"stdx",
|
||||
"test_utils",
|
||||
]
|
||||
|
||||
@ -1023,11 +1012,9 @@ name = "ra_ide"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"format-buf",
|
||||
"indexmap",
|
||||
"insta",
|
||||
"itertools 0.9.0",
|
||||
"join_to_string",
|
||||
"log",
|
||||
"ra_assists",
|
||||
"ra_cfg",
|
||||
@ -1040,6 +1027,7 @@ dependencies = [
|
||||
"ra_text_edit",
|
||||
"rand",
|
||||
"rustc-hash",
|
||||
"stdx",
|
||||
"test_utils",
|
||||
]
|
||||
|
||||
@ -1130,6 +1118,7 @@ dependencies = [
|
||||
"rustc_lexer",
|
||||
"serde",
|
||||
"smol_str",
|
||||
"stdx",
|
||||
"test_utils",
|
||||
"walkdir",
|
||||
]
|
||||
@ -1321,6 +1310,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"stdx",
|
||||
"tempfile",
|
||||
"test_utils",
|
||||
"threadpool",
|
||||
@ -1488,6 +1478,10 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdx"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "superslice"
|
||||
version = "1.0.0"
|
||||
|
@ -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" }
|
||||
|
@ -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<Assist> {
|
||||
.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<Assist> {
|
||||
.filter(|t| t != trait_token.text())
|
||||
.collect::<Vec<SmolStr>>();
|
||||
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<Assist> {
|
||||
|
||||
#[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(
|
||||
|
@ -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<Assist> {
|
||||
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<Assist> {
|
||||
.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));
|
||||
|
@ -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<Assist> {
|
||||
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);
|
||||
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(") -> Self { Self {");
|
||||
|
||||
join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
|
||||
.separator(", ")
|
||||
.surround_with(" ", " ")
|
||||
.to_buf(&mut buf);
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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<Assist> {
|
||||
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())
|
||||
|
@ -15,6 +15,8 @@ either = "1.5.3"
|
||||
anymap = "0.12.1"
|
||||
drop_bomb = "0.1.4"
|
||||
|
||||
stdx = { path = "../stdx" }
|
||||
|
||||
ra_arena = { path = "../ra_arena" }
|
||||
ra_db = { path = "../ra_db" }
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
|
@ -63,6 +63,7 @@ use ra_db::{CrateId, Edition, FileId};
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::ast;
|
||||
use rustc_hash::FxHashMap;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
@ -246,7 +247,7 @@ impl CrateDefMap {
|
||||
entries.sort_by_key(|(name, _)| name.clone());
|
||||
|
||||
for (name, def) in entries {
|
||||
*buf += &format!("{}:", name);
|
||||
format_to!(buf, "{}:", name);
|
||||
|
||||
if def.types.is_some() {
|
||||
*buf += " t";
|
||||
@ -265,7 +266,7 @@ impl CrateDefMap {
|
||||
}
|
||||
|
||||
for (name, child) in map.modules[module].children.iter() {
|
||||
let path = path.to_string() + &format!("::{}", name);
|
||||
let path = &format!("{}::{}", path, name);
|
||||
go(buf, map, &path, *child);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ ena = "0.13.1"
|
||||
log = "0.4.8"
|
||||
rustc-hash = "1.1.0"
|
||||
|
||||
stdx = { path = "../stdx" }
|
||||
|
||||
hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
|
||||
hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
|
||||
ra_arena = { path = "../ra_arena" }
|
||||
|
@ -4,6 +4,7 @@ use std::any::Any;
|
||||
|
||||
use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
|
||||
use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
|
||||
use stdx::format_to;
|
||||
|
||||
pub use hir_def::diagnostics::UnresolvedModule;
|
||||
pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
|
||||
@ -37,12 +38,11 @@ pub struct MissingFields {
|
||||
|
||||
impl Diagnostic for MissingFields {
|
||||
fn message(&self) -> String {
|
||||
use std::fmt::Write;
|
||||
let mut message = String::from("Missing structure fields:\n");
|
||||
let mut buf = String::from("Missing structure fields:\n");
|
||||
for field in &self.missed_fields {
|
||||
writeln!(message, "- {}", field).unwrap();
|
||||
format_to!(buf, "- {}", field);
|
||||
}
|
||||
message
|
||||
buf
|
||||
}
|
||||
fn source(&self) -> InFile<SyntaxNodePtr> {
|
||||
InFile { file_id: self.file, value: self.field_list.into() }
|
||||
|
@ -10,6 +10,7 @@ use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
|
||||
use ra_db::{
|
||||
salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast,
|
||||
};
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{db::HirDatabase, expr::ExprValidator};
|
||||
|
||||
@ -131,7 +132,7 @@ impl TestDB {
|
||||
for f in fns {
|
||||
let infer = self.infer(f.into());
|
||||
let mut sink = DiagnosticSink::new(|d| {
|
||||
buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message());
|
||||
format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
|
||||
});
|
||||
infer.add_diagnostics(self, f, &mut sink);
|
||||
let mut validator = ExprValidator::new(f, infer, &mut sink);
|
||||
|
@ -7,7 +7,6 @@ mod traits;
|
||||
mod method_resolution;
|
||||
mod macros;
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_def::{
|
||||
@ -26,6 +25,7 @@ use ra_syntax::{
|
||||
algo,
|
||||
ast::{self, AstNode},
|
||||
};
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult};
|
||||
|
||||
@ -63,7 +63,7 @@ fn infer(ra_fixture: &str) -> String {
|
||||
fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||
let (db, file_id) = TestDB::with_single_file(content);
|
||||
|
||||
let mut acc = String::new();
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut infer_def = |inference_result: Arc<InferenceResult>,
|
||||
body_source_map: Arc<BodySourceMap>| {
|
||||
@ -106,15 +106,14 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||
(src_ptr.value.range(), node.text().to_string().replace("\n", " "))
|
||||
};
|
||||
let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
|
||||
writeln!(
|
||||
acc,
|
||||
"{}{} '{}': {}",
|
||||
format_to!(
|
||||
buf,
|
||||
"{}{} '{}': {}\n",
|
||||
macro_prefix,
|
||||
range,
|
||||
ellipsize(text, 15),
|
||||
ty.display(&db)
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
}
|
||||
if include_mismatches {
|
||||
mismatches.sort_by_key(|(src_ptr, _)| {
|
||||
@ -123,15 +122,14 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||
for (src_ptr, mismatch) in &mismatches {
|
||||
let range = src_ptr.value.range();
|
||||
let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
|
||||
writeln!(
|
||||
acc,
|
||||
"{}{}: expected {}, got {}",
|
||||
format_to!(
|
||||
buf,
|
||||
"{}{}: expected {}, got {}\n",
|
||||
macro_prefix,
|
||||
range,
|
||||
mismatch.expected.display(&db),
|
||||
mismatch.actual.display(&db),
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -158,8 +156,8 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||
infer_def(infer, source_map);
|
||||
}
|
||||
|
||||
acc.truncate(acc.trim_end().len());
|
||||
acc
|
||||
buf.truncate(buf.trim_end().len());
|
||||
buf
|
||||
}
|
||||
|
||||
fn visit_module(
|
||||
|
@ -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" }
|
||||
|
@ -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)
|
||||
|
@ -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!(
|
||||
|
@ -6,12 +6,13 @@ mod navigation_target;
|
||||
mod structure;
|
||||
mod short_label;
|
||||
|
||||
use std::fmt::{Display, Write};
|
||||
use std::fmt::Display;
|
||||
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
|
||||
SyntaxKind::{ATTR, COMMENT},
|
||||
};
|
||||
use stdx::format_to;
|
||||
|
||||
pub use function_signature::FunctionSignature;
|
||||
pub use navigation_target::NavigationTarget;
|
||||
@ -78,18 +79,18 @@ pub(crate) fn rust_code_markup_with_doc(
|
||||
doc: Option<&str>,
|
||||
mod_path: Option<&str>,
|
||||
) -> String {
|
||||
let mut markup = "```rust\n".to_owned();
|
||||
let mut buf = "```rust\n".to_owned();
|
||||
|
||||
if let Some(mod_path) = mod_path {
|
||||
if !mod_path.is_empty() {
|
||||
write!(markup, "{}\n", mod_path).unwrap();
|
||||
format_to!(buf, "{}\n", mod_path);
|
||||
}
|
||||
}
|
||||
write!(markup, "{}\n```", code).unwrap();
|
||||
format_to!(buf, "{}\n```", code);
|
||||
|
||||
if let Some(doc) = doc {
|
||||
write!(markup, "\n\n{}", doc).unwrap();
|
||||
format_to!(buf, "\n\n{}", doc);
|
||||
}
|
||||
|
||||
markup
|
||||
buf
|
||||
}
|
||||
|
@ -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(())
|
||||
|
@ -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<String>;
|
||||
@ -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)
|
||||
|
@ -18,6 +18,8 @@ rustc-hash = "1.1.0"
|
||||
arrayvec = "0.5.1"
|
||||
once_cell = "1.3.1"
|
||||
|
||||
stdx = { path = "../stdx" }
|
||||
|
||||
ra_text_edit = { path = "../ra_text_edit" }
|
||||
ra_parser = { path = "../ra_parser" }
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This module contains free-standing functions for creating AST fragments out
|
||||
//! of smaller pieces.
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};
|
||||
|
||||
@ -34,14 +35,14 @@ pub fn use_tree(
|
||||
let mut buf = "use ".to_string();
|
||||
buf += &path.syntax().to_string();
|
||||
if let Some(use_tree_list) = use_tree_list {
|
||||
buf += &format!("::{}", use_tree_list);
|
||||
format_to!(buf, "::{}", use_tree_list);
|
||||
}
|
||||
if add_star {
|
||||
buf += "::*";
|
||||
}
|
||||
|
||||
if let Some(alias) = alias {
|
||||
buf += &format!(" {}", alias);
|
||||
format_to!(buf, " {}", alias);
|
||||
}
|
||||
ast_from_text(&buf)
|
||||
}
|
||||
@ -70,15 +71,15 @@ pub fn block_expr(
|
||||
stmts: impl IntoIterator<Item = ast::Stmt>,
|
||||
tail_expr: Option<ast::Expr>,
|
||||
) -> ast::BlockExpr {
|
||||
let mut text = "{\n".to_string();
|
||||
let mut buf = "{\n".to_string();
|
||||
for stmt in stmts.into_iter() {
|
||||
text += &format!(" {}\n", stmt);
|
||||
format_to!(buf, " {}\n", stmt);
|
||||
}
|
||||
if let Some(tail_expr) = tail_expr {
|
||||
text += &format!(" {}\n", tail_expr)
|
||||
format_to!(buf, " {}\n", tail_expr)
|
||||
}
|
||||
text += "}";
|
||||
ast_from_text(&format!("fn f() {}", text))
|
||||
buf += "}";
|
||||
ast_from_text(&format!("fn f() {}", buf))
|
||||
}
|
||||
|
||||
pub fn block_from_expr(e: ast::Expr) -> ast::Block {
|
||||
|
@ -32,9 +32,10 @@ pub mod ast;
|
||||
#[doc(hidden)]
|
||||
pub mod fuzz;
|
||||
|
||||
use std::{fmt::Write, marker::PhantomData, sync::Arc};
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
use ra_text_edit::AtomTextEdit;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::syntax_node::GreenNode;
|
||||
|
||||
@ -115,7 +116,7 @@ impl Parse<SourceFile> {
|
||||
pub fn debug_dump(&self) -> String {
|
||||
let mut buf = format!("{:#?}", self.tree().syntax());
|
||||
for err in self.errors.iter() {
|
||||
writeln!(buf, "error {:?}: {}", err.range(), err).unwrap();
|
||||
format_to!(buf, "error {:?}: {}\n", err.range(), err);
|
||||
}
|
||||
buf
|
||||
}
|
||||
@ -296,7 +297,7 @@ fn api_walkthrough() {
|
||||
NodeOrToken::Node(it) => it.text().to_string(),
|
||||
NodeOrToken::Token(it) => it.text().to_string(),
|
||||
};
|
||||
buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
|
||||
format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
|
||||
indent += 2;
|
||||
}
|
||||
WalkEvent::Leave(_) => indent -= 2,
|
||||
|
@ -30,6 +30,8 @@ serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde_json = "1.0.48"
|
||||
threadpool = "1.7.1"
|
||||
|
||||
stdx = { path = "../stdx" }
|
||||
|
||||
lsp-server = "0.3.1"
|
||||
ra_cargo_watch = { path = "../ra_cargo_watch" }
|
||||
ra_ide = { path = "../ra_ide" }
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Fully type-check project and print various stats, like the number of type
|
||||
//! errors.
|
||||
|
||||
use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
|
||||
use std::{collections::HashSet, path::Path, time::Instant};
|
||||
|
||||
use hir::{
|
||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||
@ -13,6 +13,7 @@ use itertools::Itertools;
|
||||
use ra_db::SourceDatabaseExt;
|
||||
use ra_syntax::AstNode;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity};
|
||||
|
||||
@ -128,7 +129,7 @@ pub fn analysis_stats(
|
||||
let original_file = src.file_id.original_file(db);
|
||||
let path = db.file_relative_path(original_file);
|
||||
let syntax_range = src.value.syntax().text_range();
|
||||
write!(msg, " ({:?} {})", path, syntax_range).unwrap();
|
||||
format_to!(msg, " ({:?} {})", path, syntax_range);
|
||||
}
|
||||
if verbosity.is_spammy() {
|
||||
bar.println(msg.to_string());
|
||||
|
@ -3,7 +3,6 @@
|
||||
//! `ra_ide` crate.
|
||||
|
||||
use std::{
|
||||
fmt::Write as _,
|
||||
io::Write as _,
|
||||
process::{self, Stdio},
|
||||
};
|
||||
@ -28,6 +27,7 @@ use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::to_value;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec,
|
||||
@ -46,11 +46,11 @@ use crate::{
|
||||
pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> {
|
||||
let _p = profile("handle_analyzer_status");
|
||||
let mut buf = world.status();
|
||||
writeln!(buf, "\n\nrequests:").unwrap();
|
||||
format_to!(buf, "\n\nrequests:");
|
||||
let requests = world.latest_requests.read();
|
||||
for (is_last, r) in requests.iter() {
|
||||
let mark = if is_last { "*" } else { " " };
|
||||
writeln!(buf, "{}{:4} {:<36}{}ms", mark, r.id, r.method, r.duration.as_millis()).unwrap();
|
||||
format_to!(buf, "{}{:4} {:<36}{}ms", mark, r.id, r.method, r.duration.as_millis());
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use ra_ide::{
|
||||
use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace};
|
||||
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
|
||||
use relative_path::RelativePathBuf;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{
|
||||
diagnostics::{CheckFixes, DiagnosticCollection},
|
||||
@ -319,23 +320,23 @@ impl WorldSnapshot {
|
||||
}
|
||||
|
||||
pub fn status(&self) -> String {
|
||||
let mut res = String::new();
|
||||
let mut buf = String::new();
|
||||
if self.workspaces.is_empty() {
|
||||
res.push_str("no workspaces\n")
|
||||
buf.push_str("no workspaces\n")
|
||||
} else {
|
||||
res.push_str("workspaces:\n");
|
||||
buf.push_str("workspaces:\n");
|
||||
for w in self.workspaces.iter() {
|
||||
res += &format!("{} packages loaded\n", w.n_packages());
|
||||
format_to!(buf, "{} packages loaded\n", w.n_packages());
|
||||
}
|
||||
}
|
||||
res.push_str("\nanalysis:\n");
|
||||
res.push_str(
|
||||
buf.push_str("\nanalysis:\n");
|
||||
buf.push_str(
|
||||
&self
|
||||
.analysis
|
||||
.status()
|
||||
.unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
|
||||
);
|
||||
res
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> {
|
||||
|
11
crates/stdx/Cargo.toml
Normal file
11
crates/stdx/Cargo.toml
Normal file
@ -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
|
75
crates/stdx/src/lib.rs
Normal file
75
crates/stdx/src/lib.rs
Normal file
@ -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<I> SepBy for I
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: fmt::Display,
|
||||
{
|
||||
fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self> {
|
||||
SepByBuilder::new(sep, self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SepByBuilder<'a, I> {
|
||||
sep: &'a str,
|
||||
prefix: &'a str,
|
||||
suffix: &'a str,
|
||||
iter: Cell<Option<I>>,
|
||||
}
|
||||
|
||||
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<I> 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(())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user