More orthogonal API
This commit is contained in:
parent
735aaa7b39
commit
eb46033390
@ -1,4 +1,4 @@
|
||||
use syntax::{ast, ast::Radix, AstNode};
|
||||
use syntax::{ast, ast::Radix, AstToken};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
|
||||
|
||||
@ -14,15 +14,13 @@
|
||||
// const _: i32 = 0b1010;
|
||||
// ```
|
||||
pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let literal = ctx.find_node_at_offset::<ast::Literal>()?;
|
||||
let (radix, value) = literal.as_int_number()?.value()?;
|
||||
let literal = ctx.find_node_at_offset::<ast::Literal>()?.as_int_number()?;
|
||||
let radix = literal.radix();
|
||||
let value = literal.value()?;
|
||||
let suffix = literal.suffix();
|
||||
|
||||
let range = literal.syntax().text_range();
|
||||
let group_id = GroupLabel("Convert integer base".into());
|
||||
let suffix = match literal.kind() {
|
||||
ast::LiteralKind::IntNumber { suffix } => suffix,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
for &target_radix in Radix::ALL {
|
||||
if target_radix == radix {
|
||||
@ -36,16 +34,11 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) ->
|
||||
Radix::Hexadecimal => format!("0x{:X}", value),
|
||||
};
|
||||
|
||||
let label = format!(
|
||||
"Convert {} to {}{}",
|
||||
literal,
|
||||
converted,
|
||||
suffix.as_deref().unwrap_or_default()
|
||||
);
|
||||
let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default());
|
||||
|
||||
// Appends the type suffix back into the new literal if it exists.
|
||||
if let Some(suffix) = &suffix {
|
||||
converted.push_str(&suffix);
|
||||
if let Some(suffix) = suffix {
|
||||
converted.push_str(suffix);
|
||||
}
|
||||
|
||||
acc.add_group(
|
||||
|
@ -166,6 +166,7 @@ fn value(&self) -> Option<Cow<'_, str>> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: merge `ast::RawString` and `ast::String`.
|
||||
impl HasStringValue for ast::RawString {
|
||||
fn value(&self) -> Option<Cow<'_, str>> {
|
||||
let text = self.text().as_str();
|
||||
@ -544,29 +545,46 @@ impl ast::IntNumber {
|
||||
"i8", "i16", "i32", "i64", "i128", "isize",
|
||||
];
|
||||
|
||||
// FIXME: should probably introduce string token type?
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/6308
|
||||
pub fn value(&self) -> Option<(Radix, u128)> {
|
||||
pub fn radix(&self) -> Radix {
|
||||
match self.text().get(..2).unwrap_or_default() {
|
||||
"0b" => Radix::Binary,
|
||||
"0o" => Radix::Octal,
|
||||
"0x" => Radix::Hexadecimal,
|
||||
_ => Radix::Decimal,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> Option<u128> {
|
||||
let token = self.syntax();
|
||||
|
||||
let mut text = token.text().as_str();
|
||||
for suffix in ast::IntNumber::SUFFIXES {
|
||||
if let Some(without_suffix) = text.strip_suffix(suffix) {
|
||||
text = without_suffix;
|
||||
break;
|
||||
}
|
||||
if let Some(suffix) = self.suffix() {
|
||||
text = &text[..text.len() - suffix.len()]
|
||||
}
|
||||
|
||||
let radix = self.radix();
|
||||
text = &text[radix.prefix_len()..];
|
||||
|
||||
let buf;
|
||||
if text.contains("_") {
|
||||
buf = text.replace('_', "");
|
||||
text = buf.as_str();
|
||||
};
|
||||
|
||||
let radix = Radix::identify(text)?;
|
||||
let digits = &text[radix.prefix_len()..];
|
||||
let value = u128::from_str_radix(digits, radix as u32).ok()?;
|
||||
Some((radix, value))
|
||||
let value = u128::from_str_radix(text, radix as u32).ok()?;
|
||||
Some(value)
|
||||
}
|
||||
|
||||
pub fn suffix(&self) -> Option<&str> {
|
||||
let text = self.text();
|
||||
// FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid
|
||||
// syntax, suffix is `lol`.
|
||||
ast::IntNumber::SUFFIXES.iter().find_map(|suffix| {
|
||||
if text.ends_with(suffix) {
|
||||
return Some(&text[text.len() - suffix.len()..]);
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,27 +604,6 @@ impl Radix {
|
||||
pub const ALL: &'static [Radix] =
|
||||
&[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
|
||||
|
||||
fn identify(literal_text: &str) -> Option<Self> {
|
||||
// We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible.
|
||||
if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) {
|
||||
return Some(Self::Decimal);
|
||||
}
|
||||
|
||||
let res = match &literal_text[..2] {
|
||||
"0b" => Radix::Binary,
|
||||
"0o" => Radix::Octal,
|
||||
"0x" => Radix::Hexadecimal,
|
||||
_ => Radix::Decimal,
|
||||
};
|
||||
|
||||
// Checks that all characters after the base prefix are all valid digits for that base.
|
||||
if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) {
|
||||
Some(res)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn prefix_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Decimal => 0,
|
||||
|
Loading…
Reference in New Issue
Block a user