mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
complete raw identifier with "r#" prefix
This commit is contained in:
parent
5bb123d970
commit
f536766efb
12 changed files with 304 additions and 60 deletions
|
@ -20,6 +20,9 @@ pub struct ModPath {
|
||||||
segments: Vec<Name>,
|
segments: Vec<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct EscapedModPath<'a>(&'a ModPath);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum PathKind {
|
pub enum PathKind {
|
||||||
Plain,
|
Plain,
|
||||||
|
@ -97,10 +100,12 @@ impl ModPath {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ModPath {
|
pub fn escaped(&self) -> EscapedModPath {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
EscapedModPath(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result {
|
||||||
let mut first_segment = true;
|
let mut first_segment = true;
|
||||||
let mut add_segment = |s| -> fmt::Result {
|
let mut add_segment = |s| -> fmt::Result {
|
||||||
if !first_segment {
|
if !first_segment {
|
||||||
|
@ -127,12 +132,28 @@ impl Display for ModPath {
|
||||||
f.write_str("::")?;
|
f.write_str("::")?;
|
||||||
}
|
}
|
||||||
first_segment = false;
|
first_segment = false;
|
||||||
segment.fmt(f)?;
|
if escaped {
|
||||||
|
segment.escaped().fmt(f)?
|
||||||
|
} else {
|
||||||
|
segment.fmt(f)?
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ModPath {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self._fmt(f, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for EscapedModPath<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0._fmt(f, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Name> for ModPath {
|
impl From<Name> for ModPath {
|
||||||
fn from(name: Name) -> ModPath {
|
fn from(name: Name) -> ModPath {
|
||||||
ModPath::from_segments(PathKind::Plain, iter::once(name))
|
ModPath::from_segments(PathKind::Plain, iter::once(name))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use syntax::{ast, SmolStr};
|
use syntax::{ast, SmolStr, SyntaxKind};
|
||||||
|
|
||||||
/// `Name` is a wrapper around string, which is used in hir for both references
|
/// `Name` is a wrapper around string, which is used in hir for both references
|
||||||
/// and declarations. In theory, names should also carry hygiene info, but we are
|
/// and declarations. In theory, names should also carry hygiene info, but we are
|
||||||
|
@ -10,6 +10,10 @@ use syntax::{ast, SmolStr};
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct Name(Repr);
|
pub struct Name(Repr);
|
||||||
|
|
||||||
|
/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct EscapedName<'a>(&'a Name);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
enum Repr {
|
enum Repr {
|
||||||
Text(SmolStr),
|
Text(SmolStr),
|
||||||
|
@ -25,6 +29,51 @@ impl fmt::Display for Name {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_raw_identifier(name: &str) -> bool {
|
||||||
|
let is_keyword = SyntaxKind::from_keyword(name).is_some();
|
||||||
|
is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for EscapedName<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match &self.0 .0 {
|
||||||
|
Repr::Text(text) => {
|
||||||
|
if is_raw_identifier(text) {
|
||||||
|
write!(f, "r#{}", &text)
|
||||||
|
} else {
|
||||||
|
fmt::Display::fmt(&text, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> EscapedName<'a> {
|
||||||
|
pub fn is_escaped(&self) -> bool {
|
||||||
|
match &self.0 .0 {
|
||||||
|
Repr::Text(it) => is_raw_identifier(&it),
|
||||||
|
Repr::TupleField(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the textual representation of this name as a [`SmolStr`].
|
||||||
|
/// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
|
||||||
|
/// the general case.
|
||||||
|
pub fn to_smol_str(&self) -> SmolStr {
|
||||||
|
match &self.0 .0 {
|
||||||
|
Repr::Text(it) => {
|
||||||
|
if is_raw_identifier(&it) {
|
||||||
|
SmolStr::from_iter(["r#", &it])
|
||||||
|
} else {
|
||||||
|
it.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Repr::TupleField(it) => SmolStr::new(&it.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Name {
|
impl Name {
|
||||||
/// Note: this is private to make creating name from random string hard.
|
/// Note: this is private to make creating name from random string hard.
|
||||||
/// Hopefully, this should allow us to integrate hygiene cleaner in the
|
/// Hopefully, this should allow us to integrate hygiene cleaner in the
|
||||||
|
@ -92,6 +141,10 @@ impl Name {
|
||||||
Repr::TupleField(it) => SmolStr::new(&it.to_string()),
|
Repr::TupleField(it) => SmolStr::new(&it.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn escaped(&self) -> EscapedName {
|
||||||
|
EscapedName(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsName {
|
pub trait AsName {
|
||||||
|
|
|
@ -232,10 +232,11 @@ fn add_type_alias_impl(
|
||||||
replacement_range: TextRange,
|
replacement_range: TextRange,
|
||||||
type_alias: hir::TypeAlias,
|
type_alias: hir::TypeAlias,
|
||||||
) {
|
) {
|
||||||
let alias_name = type_alias.name(ctx.db).to_smol_str();
|
let alias_name = type_alias.name(ctx.db);
|
||||||
|
let (alias_name, escaped_name) = (alias_name.to_smol_str(), alias_name.escaped().to_smol_str());
|
||||||
|
|
||||||
let label = format!("type {} =", alias_name);
|
let label = format!("type {} =", alias_name);
|
||||||
let replacement = format!("type {} = ", alias_name);
|
let replacement = format!("type {} = ", escaped_name);
|
||||||
|
|
||||||
let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label);
|
let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label);
|
||||||
item.lookup_by(format!("type {}", alias_name))
|
item.lookup_by(format!("type {}", alias_name))
|
||||||
|
|
|
@ -116,7 +116,8 @@ pub(crate) fn render_field(
|
||||||
ty: &hir::Type,
|
ty: &hir::Type,
|
||||||
) -> CompletionItem {
|
) -> CompletionItem {
|
||||||
let is_deprecated = ctx.is_deprecated(field);
|
let is_deprecated = ctx.is_deprecated(field);
|
||||||
let name = field.name(ctx.db()).to_smol_str();
|
let name = field.name(ctx.db());
|
||||||
|
let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str());
|
||||||
let mut item = CompletionItem::new(
|
let mut item = CompletionItem::new(
|
||||||
SymbolKind::Field,
|
SymbolKind::Field,
|
||||||
ctx.source_range(),
|
ctx.source_range(),
|
||||||
|
@ -131,10 +132,7 @@ pub(crate) fn render_field(
|
||||||
.set_documentation(field.docs(ctx.db()))
|
.set_documentation(field.docs(ctx.db()))
|
||||||
.set_deprecated(is_deprecated)
|
.set_deprecated(is_deprecated)
|
||||||
.lookup_by(name.clone());
|
.lookup_by(name.clone());
|
||||||
let is_keyword = SyntaxKind::from_keyword(name.as_str()).is_some();
|
item.insert_text(escaped_name);
|
||||||
if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") {
|
|
||||||
item.insert_text(format!("r#{}", name));
|
|
||||||
}
|
|
||||||
if let Some(receiver) = &dot_access.receiver {
|
if let Some(receiver) = &dot_access.receiver {
|
||||||
if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
|
if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
|
||||||
item.ref_match(ref_match, receiver.syntax().text_range().start());
|
item.ref_match(ref_match, receiver.syntax().text_range().start());
|
||||||
|
@ -235,7 +233,7 @@ fn render_resolution_pat(
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
render_resolution_simple_(ctx, local_name, import_to_add, resolution)
|
render_resolution_simple_(ctx, &local_name, import_to_add, resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_resolution_path(
|
fn render_resolution_path(
|
||||||
|
@ -274,7 +272,10 @@ fn render_resolution_path(
|
||||||
let config = completion.config;
|
let config = completion.config;
|
||||||
|
|
||||||
let name = local_name.to_smol_str();
|
let name = local_name.to_smol_str();
|
||||||
let mut item = render_resolution_simple_(ctx, local_name, import_to_add, resolution);
|
let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
|
||||||
|
if local_name.escaped().is_escaped() {
|
||||||
|
item.insert_text(local_name.escaped().to_smol_str());
|
||||||
|
}
|
||||||
// Add `<>` for generic types
|
// Add `<>` for generic types
|
||||||
let type_path_no_ty_args = matches!(
|
let type_path_no_ty_args = matches!(
|
||||||
path_ctx,
|
path_ctx,
|
||||||
|
@ -295,7 +296,7 @@ fn render_resolution_path(
|
||||||
item.lookup_by(name.clone())
|
item.lookup_by(name.clone())
|
||||||
.label(SmolStr::from_iter([&name, "<…>"]))
|
.label(SmolStr::from_iter([&name, "<…>"]))
|
||||||
.trigger_call_info()
|
.trigger_call_info()
|
||||||
.insert_snippet(cap, format!("{}<$0>", name));
|
.insert_snippet(cap, format!("{}<$0>", local_name.escaped()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +322,7 @@ fn render_resolution_path(
|
||||||
|
|
||||||
fn render_resolution_simple_(
|
fn render_resolution_simple_(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
local_name: hir::Name,
|
local_name: &hir::Name,
|
||||||
import_to_add: Option<LocatedImport>,
|
import_to_add: Option<LocatedImport>,
|
||||||
resolution: ScopeDef,
|
resolution: ScopeDef,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
|
@ -1725,4 +1726,149 @@ fn f() {
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_struct_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"type",
|
||||||
|
r#"
|
||||||
|
mod m { pub struct r#type {} }
|
||||||
|
fn main() {
|
||||||
|
let r#type = m::t$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
mod m { pub struct r#type {} }
|
||||||
|
fn main() {
|
||||||
|
let r#type = m::r#type;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_fn_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"type",
|
||||||
|
r#"
|
||||||
|
mod m { pub fn r#type {} }
|
||||||
|
fn main() {
|
||||||
|
m::t$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
mod m { pub fn r#type {} }
|
||||||
|
fn main() {
|
||||||
|
m::r#type()$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_macro_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"let!",
|
||||||
|
r#"
|
||||||
|
macro_rules! r#let { () => {} }
|
||||||
|
fn main() {
|
||||||
|
$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
macro_rules! r#let { () => {} }
|
||||||
|
fn main() {
|
||||||
|
r#let!($0)
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_variant_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"type",
|
||||||
|
r#"
|
||||||
|
enum A { r#type }
|
||||||
|
fn main() {
|
||||||
|
let a = A::t$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
enum A { r#type }
|
||||||
|
fn main() {
|
||||||
|
let a = A::r#type$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_field_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"fn",
|
||||||
|
r#"
|
||||||
|
mod r#type {
|
||||||
|
pub struct r#struct {
|
||||||
|
pub r#fn: u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = r#type::r#struct {};
|
||||||
|
a.$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
mod r#type {
|
||||||
|
pub struct r#struct {
|
||||||
|
pub r#fn: u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = r#type::r#struct {};
|
||||||
|
a.r#fn
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_const_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"type",
|
||||||
|
r#"
|
||||||
|
struct r#struct {}
|
||||||
|
impl r#struct { pub const r#type: u8 = 1; }
|
||||||
|
fn main() {
|
||||||
|
r#struct::t$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct r#struct {}
|
||||||
|
impl r#struct { pub const r#type: u8 = 1; }
|
||||||
|
fn main() {
|
||||||
|
r#struct::r#type
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_type_alias_with_raw_identifier() {
|
||||||
|
check_edit(
|
||||||
|
"type type",
|
||||||
|
r#"
|
||||||
|
struct r#struct {}
|
||||||
|
trait r#trait { type r#type; }
|
||||||
|
impl r#trait for r#struct { type t$0 }
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct r#struct {}
|
||||||
|
trait r#trait { type r#type; }
|
||||||
|
impl r#trait for r#struct { type r#type = $0; }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option
|
||||||
|
|
||||||
fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
|
fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
|
||||||
let db = ctx.db();
|
let db = ctx.db();
|
||||||
let name = const_.name(db)?.to_smol_str();
|
let name = const_.name(db)?;
|
||||||
|
let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str());
|
||||||
let detail = const_.display(db).to_string();
|
let detail = const_.display(db).to_string();
|
||||||
|
|
||||||
let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone());
|
let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone());
|
||||||
|
@ -24,9 +25,9 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem>
|
||||||
if let Some(actm) = const_.as_assoc_item(db) {
|
if let Some(actm) = const_.as_assoc_item(db) {
|
||||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||||
item.trait_name(trt.name(db).to_smol_str());
|
item.trait_name(trt.name(db).to_smol_str());
|
||||||
item.insert_text(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item.insert_text(escaped_name);
|
||||||
|
|
||||||
Some(item.build())
|
Some(item.build())
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,12 @@ fn render(
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| func.name(db));
|
let name = local_name.unwrap_or_else(|| func.name(db));
|
||||||
|
|
||||||
let call = match &func_kind {
|
let (call, escaped_call) = match &func_kind {
|
||||||
FuncKind::Method(_, Some(receiver)) => format!("{}.{}", receiver, &name).into(),
|
FuncKind::Method(_, Some(receiver)) => (
|
||||||
_ => name.to_smol_str(),
|
format!("{}.{}", receiver, &name).into(),
|
||||||
|
format!("{}.{}", receiver.escaped(), name.escaped()).into(),
|
||||||
|
),
|
||||||
|
_ => (name.to_smol_str(), name.escaped().to_smol_str()),
|
||||||
};
|
};
|
||||||
let mut item = CompletionItem::new(
|
let mut item = CompletionItem::new(
|
||||||
if func.self_param(db).is_some() {
|
if func.self_param(db).is_some() {
|
||||||
|
@ -115,7 +118,15 @@ fn render(
|
||||||
if let Some((self_param, params)) =
|
if let Some((self_param, params)) =
|
||||||
params(ctx.completion, func, &func_kind, has_dot_receiver)
|
params(ctx.completion, func, &func_kind, has_dot_receiver)
|
||||||
{
|
{
|
||||||
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
add_call_parens(
|
||||||
|
&mut item,
|
||||||
|
completion,
|
||||||
|
cap,
|
||||||
|
call,
|
||||||
|
escaped_call,
|
||||||
|
self_param,
|
||||||
|
params,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,13 +153,14 @@ pub(super) fn add_call_parens<'b>(
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
cap: SnippetCap,
|
cap: SnippetCap,
|
||||||
name: SmolStr,
|
name: SmolStr,
|
||||||
|
escaped_name: SmolStr,
|
||||||
self_param: Option<hir::SelfParam>,
|
self_param: Option<hir::SelfParam>,
|
||||||
params: Vec<hir::Param>,
|
params: Vec<hir::Param>,
|
||||||
) -> &'b mut Builder {
|
) -> &'b mut Builder {
|
||||||
cov_mark::hit!(inserts_parens_for_function_calls);
|
cov_mark::hit!(inserts_parens_for_function_calls);
|
||||||
|
|
||||||
let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() {
|
let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() {
|
||||||
(format!("{}()$0", name), "()")
|
(format!("{}()$0", escaped_name), "()")
|
||||||
} else {
|
} else {
|
||||||
builder.trigger_call_info();
|
builder.trigger_call_info();
|
||||||
let snippet = if let Some(CallableSnippets::FillArguments) = ctx.config.callable {
|
let snippet = if let Some(CallableSnippets::FillArguments) = ctx.config.callable {
|
||||||
|
@ -179,19 +191,19 @@ pub(super) fn add_call_parens<'b>(
|
||||||
Some(self_param) => {
|
Some(self_param) => {
|
||||||
format!(
|
format!(
|
||||||
"{}(${{1:{}}}{}{})$0",
|
"{}(${{1:{}}}{}{})$0",
|
||||||
name,
|
escaped_name,
|
||||||
self_param.display(ctx.db),
|
self_param.display(ctx.db),
|
||||||
if params.is_empty() { "" } else { ", " },
|
if params.is_empty() { "" } else { ", " },
|
||||||
function_params_snippet
|
function_params_snippet
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
format!("{}({})$0", name, function_params_snippet)
|
format!("{}({})$0", escaped_name, function_params_snippet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cov_mark::hit!(suppress_arg_snippets);
|
cov_mark::hit!(suppress_arg_snippets);
|
||||||
format!("{}($0)", name)
|
format!("{}($0)", escaped_name)
|
||||||
};
|
};
|
||||||
|
|
||||||
(snippet, "(…)")
|
(snippet, "(…)")
|
||||||
|
|
|
@ -72,17 +72,21 @@ fn render(
|
||||||
}
|
}
|
||||||
None => (name.clone().into(), name.into(), false),
|
None => (name.clone().into(), name.into(), false),
|
||||||
};
|
};
|
||||||
let qualified_name = qualified_name.to_string();
|
let (qualified_name, escaped_qualified_name) =
|
||||||
|
(qualified_name.to_string(), qualified_name.escaped().to_string());
|
||||||
let snippet_cap = ctx.snippet_cap();
|
let snippet_cap = ctx.snippet_cap();
|
||||||
|
|
||||||
let mut rendered = match kind {
|
let mut rendered = match kind {
|
||||||
StructKind::Tuple if should_add_parens => {
|
StructKind::Tuple if should_add_parens => {
|
||||||
render_tuple_lit(db, snippet_cap, &fields, &qualified_name)
|
render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name)
|
||||||
}
|
}
|
||||||
StructKind::Record if should_add_parens => {
|
StructKind::Record if should_add_parens => {
|
||||||
render_record_lit(db, snippet_cap, &fields, &qualified_name)
|
render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name)
|
||||||
}
|
}
|
||||||
_ => RenderedLiteral { literal: qualified_name.clone(), detail: qualified_name.clone() },
|
_ => RenderedLiteral {
|
||||||
|
literal: escaped_qualified_name.clone(),
|
||||||
|
detail: escaped_qualified_name.clone(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if snippet_cap.is_some() {
|
if snippet_cap.is_some() {
|
||||||
|
|
|
@ -46,7 +46,7 @@ fn render(
|
||||||
ctx.source_range()
|
ctx.source_range()
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = name.to_smol_str();
|
let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str());
|
||||||
let docs = ctx.docs(macro_);
|
let docs = ctx.docs(macro_);
|
||||||
let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
|
let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
|
||||||
let is_fn_like = macro_.is_fn_like(completion.db);
|
let is_fn_like = macro_.is_fn_like(completion.db);
|
||||||
|
@ -64,20 +64,18 @@ fn render(
|
||||||
.set_documentation(docs)
|
.set_documentation(docs)
|
||||||
.set_relevance(ctx.completion_relevance());
|
.set_relevance(ctx.completion_relevance());
|
||||||
|
|
||||||
let name = &*name;
|
|
||||||
match ctx.snippet_cap() {
|
match ctx.snippet_cap() {
|
||||||
Some(cap) if needs_bang && !has_call_parens => {
|
Some(cap) if needs_bang && !has_call_parens => {
|
||||||
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
let snippet = format!("{}!{}$0{}", escaped_name, bra, ket);
|
||||||
let lookup = banged_name(name);
|
let lookup = banged_name(&name);
|
||||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||||
}
|
}
|
||||||
_ if needs_bang => {
|
_ if needs_bang => {
|
||||||
let banged_name = banged_name(name);
|
item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name));
|
||||||
item.insert_text(banged_name.clone()).lookup_by(banged_name);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
||||||
item.insert_text(name);
|
item.insert_text(escaped_name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(import_to_add) = ctx.import_to_add {
|
if let Some(import_to_add) = ctx.import_to_add {
|
||||||
|
|
|
@ -27,11 +27,12 @@ pub(crate) fn render_struct_pat(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
|
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
|
||||||
|
let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str());
|
||||||
let pat = render_pat(
|
let pat = render_pat(
|
||||||
&ctx,
|
&ctx,
|
||||||
pattern_ctx,
|
pattern_ctx,
|
||||||
&name,
|
&escaped_name,
|
||||||
strukt.kind(ctx.db()),
|
strukt.kind(ctx.db()),
|
||||||
&visible_fields,
|
&visible_fields,
|
||||||
fields_omitted,
|
fields_omitted,
|
||||||
|
@ -52,14 +53,17 @@ pub(crate) fn render_variant_pat(
|
||||||
let fields = variant.fields(ctx.db());
|
let fields = variant.fields(ctx.db());
|
||||||
let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
|
let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
|
||||||
|
|
||||||
let name = match path {
|
let (name, escaped_name) = match path {
|
||||||
Some(path) => path.to_string().into(),
|
Some(path) => (path.to_string().into(), path.escaped().to_string().into()),
|
||||||
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
|
None => {
|
||||||
|
let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
|
||||||
|
(name.to_smol_str(), name.escaped().to_smol_str())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let pat = render_pat(
|
let pat = render_pat(
|
||||||
&ctx,
|
&ctx,
|
||||||
pattern_ctx,
|
pattern_ctx,
|
||||||
&name,
|
&escaped_name,
|
||||||
variant.kind(ctx.db()),
|
variant.kind(ctx.db()),
|
||||||
&visible_fields,
|
&visible_fields,
|
||||||
fields_omitted,
|
fields_omitted,
|
||||||
|
|
|
@ -29,10 +29,14 @@ fn render(
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let db = ctx.db();
|
let db = ctx.db();
|
||||||
|
|
||||||
let name = if with_eq {
|
let name = type_alias.name(db);
|
||||||
SmolStr::from_iter([&*type_alias.name(db).to_smol_str(), " = "])
|
let (name, escaped_name) = if with_eq {
|
||||||
|
(
|
||||||
|
SmolStr::from_iter([&name.to_smol_str(), " = "]),
|
||||||
|
SmolStr::from_iter([&name.escaped().to_smol_str(), " = "]),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
type_alias.name(db).to_smol_str()
|
(name.to_smol_str(), name.escaped().to_smol_str())
|
||||||
};
|
};
|
||||||
let detail = type_alias.display(db).to_string();
|
let detail = type_alias.display(db).to_string();
|
||||||
|
|
||||||
|
@ -45,9 +49,9 @@ fn render(
|
||||||
if let Some(actm) = type_alias.as_assoc_item(db) {
|
if let Some(actm) = type_alias.as_assoc_item(db) {
|
||||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||||
item.trait_name(trt.name(db).to_smol_str());
|
item.trait_name(trt.name(db).to_smol_str());
|
||||||
item.insert_text(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item.insert_text(escaped_name);
|
||||||
|
|
||||||
Some(item.build())
|
Some(item.build())
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,17 @@ pub(crate) fn render_union_literal(
|
||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
local_name: Option<Name>,
|
local_name: Option<Name>,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let name = local_name.unwrap_or_else(|| un.name(ctx.db())).to_smol_str();
|
let name = local_name.unwrap_or_else(|| un.name(ctx.db()));
|
||||||
|
|
||||||
let qualified_name = match path {
|
let (qualified_name, escaped_qualified_name) = match path {
|
||||||
Some(p) => p.to_string(),
|
Some(p) => (p.to_string(), p.escaped().to_string()),
|
||||||
None => name.to_string(),
|
None => (name.to_string(), name.escaped().to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut item = CompletionItem::new(
|
let mut item = CompletionItem::new(
|
||||||
CompletionItemKind::SymbolKind(SymbolKind::Union),
|
CompletionItemKind::SymbolKind(SymbolKind::Union),
|
||||||
ctx.source_range(),
|
ctx.source_range(),
|
||||||
format_literal_label(&name, StructKind::Record),
|
format_literal_label(&name.to_smol_str(), StructKind::Record),
|
||||||
);
|
);
|
||||||
|
|
||||||
let fields = un.fields(ctx.db());
|
let fields = un.fields(ctx.db());
|
||||||
|
@ -41,16 +41,16 @@ pub(crate) fn render_union_literal(
|
||||||
let literal = if ctx.snippet_cap().is_some() {
|
let literal = if ctx.snippet_cap().is_some() {
|
||||||
format!(
|
format!(
|
||||||
"{} {{ ${{1|{}|}}: ${{2:()}} }}$0",
|
"{} {{ ${{1|{}|}}: ${{2:()}} }}$0",
|
||||||
qualified_name,
|
escaped_qualified_name,
|
||||||
fields.iter().map(|field| field.name(ctx.db())).format(",")
|
fields.iter().map(|field| field.name(ctx.db()).escaped().to_smol_str()).format(",")
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{} {{ {} }}",
|
"{} {{ {} }}",
|
||||||
qualified_name,
|
escaped_qualified_name,
|
||||||
fields
|
fields.iter().format_with(", ", |field, f| {
|
||||||
.iter()
|
f(&format_args!("{}: ()", field.name(ctx.db()).escaped()))
|
||||||
.format_with(", ", |field, f| { f(&format_args!("{}: ()", field.name(ctx.db()))) })
|
})
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ pub(crate) fn render_record_lit(
|
||||||
) -> RenderedLiteral {
|
) -> RenderedLiteral {
|
||||||
let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
|
let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
|
||||||
if snippet_cap.is_some() {
|
if snippet_cap.is_some() {
|
||||||
f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1))
|
f(&format_args!("{}: ${{{}:()}}", field.name(db).escaped(), idx + 1))
|
||||||
} else {
|
} else {
|
||||||
f(&format_args!("{}: ()", field.name(db)))
|
f(&format_args!("{}: ()", field.name(db).escaped()))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue