diff --git a/Cargo.lock b/Cargo.lock index 5b275c7..a6b92e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,6 +520,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "line-index" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee59ea2e50e61bae4f09eee6416820f2ba9796d6e924c86f6e4f699dcb1a7ac" +dependencies = [ + "nohash-hasher", + "text-size", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -630,6 +640,12 @@ dependencies = [ "adler", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "num_threads" version = "0.1.6" @@ -1032,6 +1048,7 @@ dependencies = [ "anyhow", "clap", "directories", + "line-index", "log", "lsp-server", "lsp-types", @@ -1217,6 +1234,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + [[package]] name = "textwrap" version = "0.15.2" diff --git a/crates/stef-derive/src/cause.rs b/crates/stef-derive/src/cause.rs index 81785eb..f0634d1 100644 --- a/crates/stef-derive/src/cause.rs +++ b/crates/stef-derive/src/cause.rs @@ -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(()) } @@ -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,)* } } @@ -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,)* } } @@ -391,35 +399,35 @@ fn expand_miette( impl miette::Diagnostic for #ident { fn code(&self) -> Option> { match self { - Self::Parser(_) => None, + Self::Parser(_, _) => None, #(#codes,)* } } fn help(&self) -> Option> { match self { - Self::Parser(_) => None, + Self::Parser(_, _) => None, #(#helps,)* } } fn labels(&self) -> Option +'_>> { match self { - Self::Parser(_) => None, + Self::Parser(_, _) => None, #(#labels,)* } } fn related(&self) -> Option + '_>> { match self { - Self::Parser(_) => None, + Self::Parser(_, _) => None, #(#relateds,)* } } fn url(&self) -> Option> { match self { - Self::Parser(_) => None, + Self::Parser(_, _) => None, #(#urls,)* } } @@ -467,9 +475,12 @@ fn expand_winnow(ident: &Ident, variants: &[VariantInfo<'_>]) -> syn::Result>>()?; Ok(quote! { - impl winnow::error::ParserError for #ident { - fn from_error_kind(_: &I, kind: winnow::error::ErrorKind) -> Self { - Self::Parser(kind) + impl winnow::error::ParserError 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 { diff --git a/crates/stef-derive/src/error.rs b/crates/stef-derive/src/error.rs index 2c15d1e..d783eed 100644 --- a/crates/stef-derive/src/error.rs +++ b/crates/stef-derive/src/error.rs @@ -46,11 +46,14 @@ pub fn expand(derive: DeriveInput) -> syn::Result { #error_impl #miette_impl - impl ::winnow::error::ParserError for #ident { - fn from_error_kind(_: &I, kind: ::winnow::error::ErrorKind) -> Self { + impl ::winnow::error::ParserError 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()), } } diff --git a/crates/stef-lsp/Cargo.toml b/crates/stef-lsp/Cargo.toml index 901c38d..9f18247 100644 --- a/crates/stef-lsp/Cargo.toml +++ b/crates/stef-lsp/Cargo.toml @@ -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"] } diff --git a/crates/stef-lsp/src/compile.rs b/crates/stef-lsp/src/compile.rs index aa73741..dbf1af1 100644 --- a/crates/stef-lsp/src/compile.rs +++ b/crates/stef-lsp/src/compile.rs @@ -1,5 +1,6 @@ use std::ops::Range; +use line_index::{LineIndex, TextSize, WideEncoding}; use lsp_types::{self as lsp, Diagnostic, Url}; use stef_compiler::validate; use stef_parser::{ @@ -12,189 +13,182 @@ use stef_parser::{ Schema, }; -use crate::utf16; - pub fn compile(file: Url, schema: &str) -> std::result::Result, Diagnostic> { + let index = LineIndex::new(schema); + let parsed = stef_parser::Schema::parse(schema, None) - .map_err(|e| parse_schema_diagnostic(schema, &e))?; + .map_err(|e| parse_schema_diagnostic(&index, &e))?; stef_compiler::validate_schema(&parsed) - .map_err(|e| validate_schema_diagnostic(file, schema, e))?; + .map_err(|e| validate_schema_diagnostic(file, &index, e))?; Ok(parsed) } -fn parse_schema_diagnostic(schema: &str, e: &ParseSchemaError) -> Diagnostic { +fn parse_schema_diagnostic(index: &LineIndex, e: &ParseSchemaError) -> Diagnostic { match &e.cause { - ParseSchemaCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseSchemaCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } - ParseSchemaCause::Definition(e) => parse_definition_diagnostic(schema, e), + ParseSchemaCause::Definition(e) => parse_definition_diagnostic(index, e), } } -fn parse_definition_diagnostic(schema: &str, e: &ParseDefinitionError) -> Diagnostic { +fn parse_definition_diagnostic(index: &LineIndex, e: &ParseDefinitionError) -> Diagnostic { match e { - ParseDefinitionError::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseDefinitionError::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } - ParseDefinitionError::Comment(e) => parse_comment_diagnostic(schema, e), + ParseDefinitionError::Comment(e) => parse_comment_diagnostic(index, e), ParseDefinitionError::Attribute(e) => match &e.cause { - ParseAttributeCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseAttributeCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseAttributeCause::Literal(e) => match &e.cause { - ParseLiteralCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseLiteralCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseLiteralCause::FoundReference { at } | ParseLiteralCause::InvalidInt { at } | ParseLiteralCause::ParseInt { at, .. } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } }, }, ParseDefinitionError::Module(e) => match &e.cause { - ParseModuleCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseModuleCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseModuleCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseModuleCause::Definition(e) => parse_definition_diagnostic(schema, e), + ParseModuleCause::Definition(e) => parse_definition_diagnostic(index, e), }, ParseDefinitionError::Struct(e) => match &e.cause { - ParseStructCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseStructCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseStructCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseStructCause::Generics(e) => parse_generics_diagnostic(schema, e), - ParseStructCause::Fields(e) => parse_fields_diagnostic(schema, e), + ParseStructCause::Generics(e) => parse_generics_diagnostic(index, e), + ParseStructCause::Fields(e) => parse_fields_diagnostic(index, e), }, ParseDefinitionError::Enum(e) => match &e.cause { - ParseEnumCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseEnumCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseEnumCause::InvalidName { at } | ParseEnumCause::InvalidVariantName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseEnumCause::Generics(e) => parse_generics_diagnostic(schema, e), - ParseEnumCause::Field(e) => parse_fields_diagnostic(schema, e), - ParseEnumCause::Comment(e) => parse_comment_diagnostic(schema, e), - ParseEnumCause::Id(e) => parse_id_diagnostic(schema, e), + ParseEnumCause::Generics(e) => parse_generics_diagnostic(index, e), + ParseEnumCause::Field(e) => parse_fields_diagnostic(index, e), + ParseEnumCause::Comment(e) => parse_comment_diagnostic(index, e), + ParseEnumCause::Id(e) => parse_id_diagnostic(index, e), }, ParseDefinitionError::Const(e) => match &e.cause { - ParseConstCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseConstCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseConstCause::UnexpectedChar { at, .. } | ParseConstCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseConstCause::Type(e) => parse_type_diagnostic(schema, e), + ParseConstCause::Type(e) => parse_type_diagnostic(index, e), ParseConstCause::Literal(e) => match &e.cause { - ParseLiteralCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseLiteralCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseLiteralCause::FoundReference { at } | ParseLiteralCause::InvalidInt { at } | ParseLiteralCause::ParseInt { at, .. } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } }, }, ParseDefinitionError::Alias(e) => match &e.cause { - ParseAliasCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseAliasCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseAliasCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseAliasCause::Generics(e) => parse_generics_diagnostic(schema, e), - ParseAliasCause::Type(e) => parse_type_diagnostic(schema, e), + ParseAliasCause::Generics(e) => parse_generics_diagnostic(index, e), + ParseAliasCause::Type(e) => parse_type_diagnostic(index, e), }, - ParseDefinitionError::Import(e) => parse_import_cause_diagnostic(schema, &e.cause), + ParseDefinitionError::Import(e) => parse_import_cause_diagnostic(index, &e.cause), } } -fn parse_type_diagnostic(schema: &str, e: &ParseTypeError) -> Diagnostic { +fn parse_type_diagnostic(index: &LineIndex, e: &ParseTypeError) -> Diagnostic { match &e.cause { - ParseTypeCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseTypeCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } - ParseTypeCause::Type(e) => parse_type_diagnostic(schema, e), - ParseTypeCause::Segment(c) => parse_import_cause_diagnostic(schema, c), + ParseTypeCause::Type(e) => parse_type_diagnostic(index, e), + ParseTypeCause::Segment(c) => parse_import_cause_diagnostic(index, c), } } -fn parse_comment_diagnostic(schema: &str, e: &ParseCommentError) -> Diagnostic { - Diagnostic::new_simple(get_range(schema, e.at.clone()), e.to_string()) +fn parse_comment_diagnostic(index: &LineIndex, e: &ParseCommentError) -> Diagnostic { + Diagnostic::new_simple(get_range(index, e.at.clone()), e.to_string()) } -fn parse_import_cause_diagnostic(schema: &str, c: &ParseImportCause) -> Diagnostic { +fn parse_import_cause_diagnostic(index: &LineIndex, c: &ParseImportCause) -> Diagnostic { match c { - ParseImportCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), c.to_string()) - } - ParseImportCause::InvalidSegmentName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), c.to_string()) + ParseImportCause::Parser(_, at) | ParseImportCause::InvalidSegmentName { at } => { + Diagnostic::new_simple(get_range(index, *at..*at), c.to_string()) } ParseImportCause::StructName(c) => match c { - ParseStructCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), c.to_string()) + ParseStructCause::Parser(_, at) | ParseStructCause::InvalidName { at } => { + Diagnostic::new_simple(get_range(index, *at..*at), c.to_string()) } - ParseStructCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), c.to_string()) - } - ParseStructCause::Generics(e) => parse_generics_diagnostic(schema, e), - ParseStructCause::Fields(e) => parse_fields_diagnostic(schema, e), + ParseStructCause::Generics(e) => parse_generics_diagnostic(index, e), + ParseStructCause::Fields(e) => parse_fields_diagnostic(index, e), }, ParseImportCause::EnumName(c) => match c { - ParseEnumCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), c.to_string()) - } - ParseEnumCause::InvalidName { at } | ParseEnumCause::InvalidVariantName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), c.to_string()) + ParseEnumCause::Parser(_, at) + | ParseEnumCause::InvalidName { at } + | ParseEnumCause::InvalidVariantName { at } => { + Diagnostic::new_simple(get_range(index, *at..*at), c.to_string()) } - ParseEnumCause::Generics(e) => parse_generics_diagnostic(schema, e), - ParseEnumCause::Field(e) => parse_fields_diagnostic(schema, e), - ParseEnumCause::Comment(e) => parse_comment_diagnostic(schema, e), - ParseEnumCause::Id(e) => parse_id_diagnostic(schema, e), + ParseEnumCause::Generics(e) => parse_generics_diagnostic(index, e), + ParseEnumCause::Field(e) => parse_fields_diagnostic(index, e), + ParseEnumCause::Comment(e) => parse_comment_diagnostic(index, e), + ParseEnumCause::Id(e) => parse_id_diagnostic(index, e), }, } } -fn parse_generics_diagnostic(schema: &str, e: &ParseGenericsError) -> Diagnostic { +fn parse_generics_diagnostic(index: &LineIndex, e: &ParseGenericsError) -> Diagnostic { match &e.cause { - stef_parser::error::ParseGenericsCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + stef_parser::error::ParseGenericsCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } stef_parser::error::ParseGenericsCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } } } -fn parse_fields_diagnostic(schema: &str, e: &ParseFieldsError) -> Diagnostic { +fn parse_fields_diagnostic(index: &LineIndex, e: &ParseFieldsError) -> Diagnostic { match &e.cause { - ParseFieldsCause::Parser(_) => { - Diagnostic::new_simple(get_range(schema, 0..schema.len()), e.to_string()) + ParseFieldsCause::Parser(_, at) => { + Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) } ParseFieldsCause::InvalidName { at } => { - Diagnostic::new_simple(get_range(schema, *at..*at), e.cause.to_string()) + Diagnostic::new_simple(get_range(index, *at..*at), e.cause.to_string()) } - ParseFieldsCause::Type(e) => parse_type_diagnostic(schema, e), - ParseFieldsCause::Id(e) => parse_id_diagnostic(schema, e), - ParseFieldsCause::Comment(e) => parse_comment_diagnostic(schema, e), + ParseFieldsCause::Type(e) => parse_type_diagnostic(index, e), + ParseFieldsCause::Id(e) => parse_id_diagnostic(index, e), + ParseFieldsCause::Comment(e) => parse_comment_diagnostic(index, e), } } -fn parse_id_diagnostic(schema: &str, e: &ParseIdError) -> Diagnostic { - Diagnostic::new_simple(get_range(schema, e.at.clone()), e.to_string()) +fn parse_id_diagnostic(index: &LineIndex, e: &ParseIdError) -> Diagnostic { + Diagnostic::new_simple(get_range(index, e.at.clone()), e.to_string()) } -fn validate_schema_diagnostic(file: Url, schema: &str, e: validate::Error) -> Diagnostic { +fn validate_schema_diagnostic(file: Url, index: &LineIndex, e: validate::Error) -> Diagnostic { use validate::{DuplicateFieldId, DuplicateId, DuplicateName, Error, InvalidGenericType}; let (message, first, second) = match e { @@ -214,20 +208,20 @@ fn validate_schema_diagnostic(file: Url, schema: &str, e: validate::Error) -> Di InvalidGenericType::Duplicate(e) => (e.to_string(), e.first, e.second), InvalidGenericType::Unused(e) => { let message = e.to_string(); - return Diagnostic::new_simple(get_range(schema, e.declared), message); + return Diagnostic::new_simple(get_range(index, e.declared), message); } }, Error::TupleSize(e) => { let message = e.to_string(); - return Diagnostic::new_simple(get_range(schema, e.declared), message); + return Diagnostic::new_simple(get_range(index, e.declared), message); } }; diagnostic_with_related( - get_range(schema, second), + get_range(index, second), message, vec![lsp::DiagnosticRelatedInformation { - location: lsp::Location::new(file, get_range(schema, first)), + location: lsp::Location::new(file, get_range(index, first)), message: "first used here".to_owned(), }], ) @@ -241,19 +235,24 @@ fn diagnostic_with_related( Diagnostic::new(range, None, None, None, message, Some(related), None) } -#[allow(clippy::cast_possible_truncation)] -fn get_range(schema: &str, location: Range) -> lsp::Range { - let start_line = schema[..location.start].lines().count().saturating_sub(1); - let start_char = schema[..location.start] - .lines() - .last() - .map_or(0, utf16::len); +#[allow(clippy::cast_possible_truncation, clippy::expect_used)] +fn get_range(index: &LineIndex, location: Range) -> lsp::Range { + let start = index + .to_wide( + WideEncoding::Utf16, + index.line_col(TextSize::new(location.start as u32)), + ) + .expect("missing utf-16 start position"); - let end_line = schema[..location.end].lines().count().saturating_sub(1); - let end_char = schema[..location.end].lines().last().map_or(0, utf16::len); + let end = index + .to_wide( + WideEncoding::Utf16, + index.line_col(TextSize::new(location.end as u32)), + ) + .expect("missing utf-16 end position"); lsp::Range::new( - lsp::Position::new(start_line as u32, start_char as u32), - lsp::Position::new(end_line as u32, end_char as u32), + lsp::Position::new(start.line, start.col), + lsp::Position::new(end.line, end.col), ) } diff --git a/crates/stef-lsp/src/main.rs b/crates/stef-lsp/src/main.rs index b02ba4d..121c852 100644 --- a/crates/stef-lsp/src/main.rs +++ b/crates/stef-lsp/src/main.rs @@ -17,11 +17,12 @@ use lsp_types::{ }, ConfigurationItem, ConfigurationParams, Diagnostic, DidChangeConfigurationParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, - InitializeParams, InitializeResult, InitializedParams, PublishDiagnosticsParams, Registration, - RegistrationParams, SemanticTokenModifier, SemanticTokenType, SemanticTokens, - SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, SemanticTokensParams, - SemanticTokensResult, SemanticTokensServerCapabilities, ServerCapabilities, ServerInfo, - TextDocumentSyncCapability, TextDocumentSyncKind, Url, WorkDoneProgressOptions, + InitializeParams, InitializeResult, InitializedParams, PositionEncodingKind, + PublishDiagnosticsParams, Registration, RegistrationParams, SemanticTokenModifier, + SemanticTokenType, SemanticTokens, SemanticTokensFullOptions, SemanticTokensLegend, + SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, + SemanticTokensServerCapabilities, ServerCapabilities, ServerInfo, TextDocumentSyncCapability, + TextDocumentSyncKind, Url, WorkDoneProgressOptions, }; use ouroboros::self_referencing; use stef_parser::Schema; @@ -32,7 +33,6 @@ mod cli; mod compile; mod config; mod logging; -mod utf16; struct Backend { conn: Connection, @@ -161,6 +161,7 @@ impl LanguageServer for Backend { version: Some(env!("CARGO_PKG_VERSION").to_owned()), }), capabilities: ServerCapabilities { + position_encoding: Some(PositionEncodingKind::UTF16), text_document_sync: Some(TextDocumentSyncCapability::Kind( TextDocumentSyncKind::FULL, )), diff --git a/crates/stef-lsp/src/utf16.rs b/crates/stef-lsp/src/utf16.rs deleted file mode 100644 index 9661f2c..0000000 --- a/crates/stef-lsp/src/utf16.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Utilities for handling UTF-16 encoding of strings. -//! -//! As the LSP by default uses UTF-16 and Rust strings are encoded as UTF-8, special handling is -//! required to calculate the correct information. Mostly these are adjustments to character -//! offsets. - -/// Get the UTF-16 byte count for the code line. -pub fn len(line: &str) -> usize { - line.encode_utf16().count() -} diff --git a/crates/stef-parser/src/error.rs b/crates/stef-parser/src/error.rs index ef7151e..15ebf6e 100644 --- a/crates/stef-parser/src/error.rs +++ b/crates/stef-parser/src/error.rs @@ -78,7 +78,7 @@ impl Diagnostic for ParseSchemaError { #[derive(Debug, Diagnostic)] pub enum ParseSchemaCause { - Parser(ErrorKind), + Parser(ErrorKind, usize), #[diagnostic(transparent)] Definition(ParseDefinitionError), } @@ -86,7 +86,7 @@ pub enum ParseSchemaCause { impl Error for ParseSchemaCause { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { - Self::Parser(kind) => kind.source(), + Self::Parser(kind, _) => kind.source(), Self::Definition(inner) => inner.source(), } } @@ -95,7 +95,7 @@ impl Error for ParseSchemaCause { impl Display for ParseSchemaCause { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Parser(kind) => kind.fmt(f), + Self::Parser(kind, _) => kind.fmt(f), Self::Definition(inner) => inner.fmt(f), } } @@ -107,9 +107,12 @@ impl From for ParseSchemaCause { } } -impl winnow::error::ParserError for ParseSchemaCause { - fn from_error_kind(_: &I, kind: winnow::error::ErrorKind) -> Self { - Self::Parser(kind) +impl winnow::error::ParserError for ParseSchemaCause +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 { @@ -120,7 +123,7 @@ impl winnow::error::ParserError for ParseSchemaCause { /// Reason why a single definition was invalid. #[derive(Debug, Diagnostic)] pub enum ParseDefinitionError { - Parser(ErrorKind), + Parser(ErrorKind, usize), #[diagnostic(transparent)] Comment(ParseCommentError), #[diagnostic(transparent)] @@ -142,7 +145,7 @@ pub enum ParseDefinitionError { impl Error for ParseDefinitionError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { - Self::Parser(kind) => kind.source(), + Self::Parser(kind, _) => kind.source(), Self::Comment(inner) => inner.source(), Self::Attribute(inner) => inner.source(), Self::Module(inner) => inner.source(), @@ -158,7 +161,7 @@ impl Error for ParseDefinitionError { impl Display for ParseDefinitionError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Parser(kind) => kind.fmt(f), + Self::Parser(kind, _) => kind.fmt(f), Self::Comment(inner) => inner.fmt(f), Self::Attribute(inner) => inner.fmt(f), Self::Module(inner) => inner.fmt(f), @@ -219,9 +222,12 @@ impl From for ParseDefinitionError { } } -impl winnow::error::ParserError for ParseDefinitionError { - fn from_error_kind(_: &I, kind: winnow::error::ErrorKind) -> Self { - Self::Parser(kind) +impl winnow::error::ParserError for ParseDefinitionError +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 { diff --git a/crates/stef-parser/src/parser.rs b/crates/stef-parser/src/parser.rs index 3174c82..3125fda 100644 --- a/crates/stef-parser/src/parser.rs +++ b/crates/stef-parser/src/parser.rs @@ -116,7 +116,7 @@ mod ids { #[derive(Debug, ParserErrorCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), } pub(super) fn parse(input: &mut Input<'_>) -> Result { @@ -130,7 +130,7 @@ mod ids { .map_err(|e| { e.map(|e: ErrorKind| ParseError { at: input.location()..input.location(), - cause: Cause::Parser(e), + cause: Cause::Parser(e, input.location()), }) }) } @@ -175,7 +175,7 @@ mod comments { #[derive(Debug, ParserErrorCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), } pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> { diff --git a/crates/stef-parser/src/parser/aliases.rs b/crates/stef-parser/src/parser/aliases.rs index 6f5876f..40e765e 100644 --- a/crates/stef-parser/src/parser/aliases.rs +++ b/crates/stef-parser/src/parser/aliases.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseAliasCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid alias name"), diff --git a/crates/stef-parser/src/parser/attributes.rs b/crates/stef-parser/src/parser/attributes.rs index 1685bec..a1655c1 100644 --- a/crates/stef-parser/src/parser/attributes.rs +++ b/crates/stef-parser/src/parser/attributes.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseAttributeCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Invalid literal for the attribute value. #[forward] Literal(literals::ParseError), diff --git a/crates/stef-parser/src/parser/consts.rs b/crates/stef-parser/src/parser/consts.rs index 53506d2..57b8149 100644 --- a/crates/stef-parser/src/parser/consts.rs +++ b/crates/stef-parser/src/parser/consts.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseConstCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), #[err( msg("Unexpected character"), code(stef::parse::const_def::char), diff --git a/crates/stef-parser/src/parser/enums.rs b/crates/stef-parser/src/parser/enums.rs index 82e9260..3993f43 100644 --- a/crates/stef-parser/src/parser/enums.rs +++ b/crates/stef-parser/src/parser/enums.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseEnumCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid enum name"), diff --git a/crates/stef-parser/src/parser/fields.rs b/crates/stef-parser/src/parser/fields.rs index 07ee2fd..39599f3 100644 --- a/crates/stef-parser/src/parser/fields.rs +++ b/crates/stef-parser/src/parser/fields.rs @@ -40,7 +40,7 @@ pub struct ParseError { #[rename(ParseFieldsCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid field name"), diff --git a/crates/stef-parser/src/parser/generics.rs b/crates/stef-parser/src/parser/generics.rs index 0ce2d3d..2d93655 100644 --- a/crates/stef-parser/src/parser/generics.rs +++ b/crates/stef-parser/src/parser/generics.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseGenericsCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err(msg("TODO!"), code(stef::parse::generics::invalid_name), help("TODO!"))] InvalidName { diff --git a/crates/stef-parser/src/parser/imports.rs b/crates/stef-parser/src/parser/imports.rs index 839911d..13f1f5b 100644 --- a/crates/stef-parser/src/parser/imports.rs +++ b/crates/stef-parser/src/parser/imports.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseImportCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid segment name"), diff --git a/crates/stef-parser/src/parser/literals.rs b/crates/stef-parser/src/parser/literals.rs index 5c64df1..e5576f3 100644 --- a/crates/stef-parser/src/parser/literals.rs +++ b/crates/stef-parser/src/parser/literals.rs @@ -47,7 +47,7 @@ pub struct ParseError { #[rename(ParseLiteralCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Found a reference value, which is not allowed. #[err( msg("Found a reference value"), diff --git a/crates/stef-parser/src/parser/modules.rs b/crates/stef-parser/src/parser/modules.rs index 6f4dd17..8f65124 100644 --- a/crates/stef-parser/src/parser/modules.rs +++ b/crates/stef-parser/src/parser/modules.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseModuleCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid module name"), diff --git a/crates/stef-parser/src/parser/structs.rs b/crates/stef-parser/src/parser/structs.rs index 72a6e63..001d381 100644 --- a/crates/stef-parser/src/parser/structs.rs +++ b/crates/stef-parser/src/parser/structs.rs @@ -37,7 +37,7 @@ pub struct ParseError { #[rename(ParseStructCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Defined name is not considered valid. #[err( msg("Invalid struct name"), diff --git a/crates/stef-parser/src/parser/types.rs b/crates/stef-parser/src/parser/types.rs index d4766ca..c39a726 100644 --- a/crates/stef-parser/src/parser/types.rs +++ b/crates/stef-parser/src/parser/types.rs @@ -40,7 +40,7 @@ pub struct ParseError { #[rename(ParseTypeCause)] pub enum Cause { /// Non-specific general parser error. - Parser(ErrorKind), + Parser(ErrorKind, usize), /// Invalid type declaration. #[forward] Type(Box),