Skip to content

Commit

Permalink
feat(lsp): improve overall handling of code locations
Browse files Browse the repository at this point in the history
The first thing is the introduction of the `line-index` crate from
rust-analyzer, which makes utf-16 conversions simple and fast.

In addition, the `Parser` error variant now carries the location of
where it occurred, rather than highlighting the whole schema file as the
location.
  • Loading branch information
dnaka91 committed Dec 12, 2023
1 parent 51645a8 commit dc61f6e
Show file tree
Hide file tree
Showing 20 changed files with 198 additions and 164 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 25 additions & 14 deletions crates/stef-derive/src/cause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,29 @@ fn is_parser_variant(variant: &Variant) -> syn::Result<()> {
bail!(variant, "first variant must be unnamed");
};

let Some(field) = fields.unnamed.first().filter(|_| fields.unnamed.len() == 1) else {
if fields.unnamed.len() != 2 {
bail!(
fields,
"first variant must only contain a single unnamed field"
"first variant must contain exactly two unnamed fields"
);
};

let Type::Path(ty) = &field.ty else {
bail!(field, "first variant type invalid");
let Type::Path(ty) = &fields.unnamed[0].ty else {
bail!(fields.unnamed[0], "first variant type invalid");
};

if !compare_path(ty, &[&["ErrorKind"], &["winnow", "error", "ErrorKind"]]) {
bail!(ty, "first variant type must be `ErrorKind`");
}

let Type::Path(ty) = &fields.unnamed[1].ty else {
bail!(fields.unnamed[1], "second variant type invalid");
};

if !compare_path(ty, &[&["usize"]]) {
bail!(ty, "second variant type must be `usize`");
}

Ok(())
}

Expand Down Expand Up @@ -220,7 +228,7 @@ fn expand_error(ident: &Ident, variants: &[VariantInfo<'_>]) -> TokenStream {
impl std::error::Error for #ident {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Parser(kind) => None,
Self::Parser(_, _) => None,
#(#sources,)*
}
}
Expand All @@ -229,7 +237,7 @@ fn expand_error(ident: &Ident, variants: &[VariantInfo<'_>]) -> TokenStream {
impl std::fmt::Display for #ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Parser(kind) => kind.fmt(f),
Self::Parser(kind, _) => kind.fmt(f),
#(#fmts,)*
}
}
Expand Down Expand Up @@ -391,35 +399,35 @@ fn expand_miette(
impl miette::Diagnostic for #ident {
fn code(&self) -> Option<Box<dyn std::fmt::Display + '_>> {
match self {
Self::Parser(_) => None,
Self::Parser(_, _) => None,
#(#codes,)*
}
}

fn help(&self) -> Option<Box<dyn std::fmt::Display + '_>> {
match self {
Self::Parser(_) => None,
Self::Parser(_, _) => None,
#(#helps,)*
}
}

fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> +'_>> {
match self {
Self::Parser(_) => None,
Self::Parser(_, _) => None,
#(#labels,)*
}
}

fn related(&self) -> Option<Box<dyn Iterator<Item = &dyn miette::Diagnostic> + '_>> {
match self {
Self::Parser(_) => None,
Self::Parser(_, _) => None,
#(#relateds,)*
}
}

fn url(&self) -> Option<Box<dyn std::fmt::Display + '_>> {
match self {
Self::Parser(_) => None,
Self::Parser(_, _) => None,
#(#urls,)*
}
}
Expand Down Expand Up @@ -467,9 +475,12 @@ fn expand_winnow(ident: &Ident, variants: &[VariantInfo<'_>]) -> syn::Result<Tok
}).collect::<syn::Result<Vec<_>>>()?;

Ok(quote! {
impl<I> winnow::error::ParserError<I> for #ident {
fn from_error_kind(_: &I, kind: winnow::error::ErrorKind) -> Self {
Self::Parser(kind)
impl<I> winnow::error::ParserError<I> for #ident
where
I: winnow::stream::Location,
{
fn from_error_kind(input: &I, kind: winnow::error::ErrorKind) -> Self {
Self::Parser(kind, input.location())
}

fn append(self, _: &I, _: winnow::error::ErrorKind) -> Self {
Expand Down
11 changes: 7 additions & 4 deletions crates/stef-derive/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,14 @@ pub fn expand(derive: DeriveInput) -> syn::Result<TokenStream> {
#error_impl
#miette_impl

impl<I> ::winnow::error::ParserError<I> for #ident {
fn from_error_kind(_: &I, kind: ::winnow::error::ErrorKind) -> Self {
impl<I> ::winnow::error::ParserError<I> for #ident
where
I: ::winnow::stream::Location,
{
fn from_error_kind(input: &I, kind: ::winnow::error::ErrorKind) -> Self {
Self{
at: Default::default(),
cause: Cause::Parser(kind),
at: input.location()..input.location(),
cause: Cause::Parser(kind, input.location()),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/stef-lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ license.workspace = true
anyhow = "1.0.75"
clap.workspace = true
directories = "5.0.1"
line-index = "0.1.0"
log = { version = "0.4.20", features = ["kv_unstable_std", "std"] }
lsp-server = "0.7.5"
lsp-types = { version = "0.94.1", features = ["proposed"] }
Expand Down
Loading

0 comments on commit dc61f6e

Please sign in to comment.