From e6d48848a6e23bf5fd1c43a905ea4904fa0adf9a Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 14 Feb 2024 15:02:18 +0900 Subject: [PATCH] feat(lsp): support all official position encodings Until now the server always assumed UTF-16, as that is the default in Visual Studio Code, but other editors like Neovim might ask for a different encoding. This now allows to run the LSP server with any of the official encodings UTF-8, UTF-16 and UTF-32. --- crates/mabo-lsp/src/handlers/compile.rs | 52 ++++-------- .../mabo-lsp/src/handlers/document_symbols.rs | 73 ++++++----------- crates/mabo-lsp/src/handlers/hover.rs | 50 ++--------- crates/mabo-lsp/src/handlers/index.rs | 82 +++++++++++++++++++ crates/mabo-lsp/src/handlers/mod.rs | 64 +++++++-------- .../mabo-lsp/src/handlers/semantic_tokens.rs | 61 ++++++-------- crates/mabo-lsp/src/main.rs | 10 +-- crates/mabo-lsp/src/state.rs | 20 +++-- 8 files changed, 207 insertions(+), 205 deletions(-) create mode 100644 crates/mabo-lsp/src/handlers/index.rs diff --git a/crates/mabo-lsp/src/handlers/compile.rs b/crates/mabo-lsp/src/handlers/compile.rs index 144ca66..bb8434e 100644 --- a/crates/mabo-lsp/src/handlers/compile.rs +++ b/crates/mabo-lsp/src/handlers/compile.rs @@ -1,6 +1,5 @@ use std::ops::Range; -use line_index::{LineIndex, TextSize, WideEncoding}; use lsp_types::{self as lsp, Diagnostic, Url}; use mabo_compiler::validate; use mabo_parser::{ @@ -13,11 +12,9 @@ use mabo_parser::{ Schema, }; -pub fn compile<'a>( - file: Url, - schema: &'a str, - index: &'_ LineIndex, -) -> Result, Diagnostic> { +use super::index::Index; + +pub fn compile<'a>(file: Url, schema: &'a str, index: &'_ Index) -> Result, Diagnostic> { let parsed = mabo_parser::Schema::parse(schema, None).map_err(|e| parse_schema_diagnostic(index, &e))?; @@ -33,7 +30,7 @@ pub fn simplify<'a>( result.as_ref().map(mabo_compiler::simplify_schema) } -fn parse_schema_diagnostic(index: &LineIndex, e: &ParseSchemaError) -> Diagnostic { +fn parse_schema_diagnostic(index: &Index, e: &ParseSchemaError) -> Diagnostic { match &e.cause { ParseSchemaCause::Parser(_, at) => { Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) @@ -43,7 +40,7 @@ fn parse_schema_diagnostic(index: &LineIndex, e: &ParseSchemaError) -> Diagnosti } } -fn parse_definition_diagnostic(index: &LineIndex, e: &ParseDefinitionError) -> Diagnostic { +fn parse_definition_diagnostic(index: &Index, e: &ParseDefinitionError) -> Diagnostic { match e { ParseDefinitionError::Parser(_, at) => { Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) @@ -128,7 +125,7 @@ fn parse_definition_diagnostic(index: &LineIndex, e: &ParseDefinitionError) -> D } } -fn parse_type_diagnostic(index: &LineIndex, e: &ParseTypeError) -> Diagnostic { +fn parse_type_diagnostic(index: &Index, e: &ParseTypeError) -> Diagnostic { match &e.cause { ParseTypeCause::Parser(_, at) => { Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) @@ -138,11 +135,11 @@ fn parse_type_diagnostic(index: &LineIndex, e: &ParseTypeError) -> Diagnostic { } } -fn parse_comment_diagnostic(index: &LineIndex, e: &ParseCommentError) -> Diagnostic { +fn parse_comment_diagnostic(index: &Index, e: &ParseCommentError) -> Diagnostic { Diagnostic::new_simple(get_range(index, e.at.clone()), e.to_string()) } -fn parse_import_cause_diagnostic(index: &LineIndex, c: &ParseImportCause) -> Diagnostic { +fn parse_import_cause_diagnostic(index: &Index, c: &ParseImportCause) -> Diagnostic { match c { ParseImportCause::Parser(_, at) | ParseImportCause::InvalidSegmentName { at } => { Diagnostic::new_simple(get_range(index, *at..*at), c.to_string()) @@ -168,7 +165,7 @@ fn parse_import_cause_diagnostic(index: &LineIndex, c: &ParseImportCause) -> Dia } } -fn parse_generics_diagnostic(index: &LineIndex, e: &ParseGenericsError) -> Diagnostic { +fn parse_generics_diagnostic(index: &Index, e: &ParseGenericsError) -> Diagnostic { match &e.cause { mabo_parser::error::ParseGenericsCause::Parser(_, at) => { Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) @@ -179,7 +176,7 @@ fn parse_generics_diagnostic(index: &LineIndex, e: &ParseGenericsError) -> Diagn } } -fn parse_fields_diagnostic(index: &LineIndex, e: &ParseFieldsError) -> Diagnostic { +fn parse_fields_diagnostic(index: &Index, e: &ParseFieldsError) -> Diagnostic { match &e.cause { ParseFieldsCause::Parser(_, at) => { Diagnostic::new_simple(get_range(index, *at..*at), e.to_string()) @@ -193,11 +190,11 @@ fn parse_fields_diagnostic(index: &LineIndex, e: &ParseFieldsError) -> Diagnosti } } -fn parse_id_diagnostic(index: &LineIndex, e: &ParseIdError) -> Diagnostic { +fn parse_id_diagnostic(index: &Index, e: &ParseIdError) -> Diagnostic { Diagnostic::new_simple(get_range(index, e.at.clone()), e.to_string()) } -fn validate_schema_diagnostic(file: Url, index: &LineIndex, e: validate::Error) -> Diagnostic { +fn validate_schema_diagnostic(file: Url, index: &Index, e: validate::Error) -> Diagnostic { use validate::{DuplicateFieldId, DuplicateId, DuplicateName, Error, InvalidGenericType}; let (message, first, second) = match e { @@ -244,24 +241,9 @@ fn diagnostic_with_related( Diagnostic::new(range, None, None, None, message, Some(related), None) } -#[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 = 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, start.col), - lsp::Position::new(end.line, end.col), - ) +#[allow(clippy::expect_used)] +fn get_range(index: &Index, location: Range) -> lsp::Range { + index + .get_range(location) + .expect("missing range information") } diff --git a/crates/mabo-lsp/src/handlers/document_symbols.rs b/crates/mabo-lsp/src/handlers/document_symbols.rs index 52a2c97..9b44eee 100644 --- a/crates/mabo-lsp/src/handlers/document_symbols.rs +++ b/crates/mabo-lsp/src/handlers/document_symbols.rs @@ -1,21 +1,22 @@ use std::{fmt::Write, ops::Range}; -use anyhow::{Context, Result}; -use line_index::{LineIndex, TextSize}; -use lsp_types::{DocumentSymbol, Position, Range as LspRange, SymbolKind}; +use anyhow::Result; +use lsp_types::{self as lsp, DocumentSymbol, SymbolKind}; use mabo_parser::{ - Const, Definition, Enum, Fields, Import, Module, NamedField, Schema, Span, Spanned, Struct, + Const, Definition, Enum, Fields, Import, Module, NamedField, Schema, Spanned, Struct, TypeAlias, UnnamedField, Variant, }; -pub fn visit_schema(index: &LineIndex, item: &Schema<'_>) -> Result> { +use super::index::Index; + +pub fn visit_schema(index: &Index, item: &Schema<'_>) -> Result> { item.definitions .iter() .map(|def| visit_definition(index, def)) .collect() } -fn visit_definition(index: &LineIndex, item: &Definition<'_>) -> Result { +fn visit_definition(index: &Index, item: &Definition<'_>) -> Result { match item { Definition::Module(m) => visit_module(index, m), Definition::Struct(s) => visit_struct(index, s), @@ -26,11 +27,11 @@ fn visit_definition(index: &LineIndex, item: &Definition<'_>) -> Result) -> Result { +fn visit_module(index: &Index, item: &Module<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::MODULE, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, item.definitions .iter() .map(|def| visit_definition(index, def)) @@ -38,20 +39,20 @@ fn visit_module(index: &LineIndex, item: &Module<'_>) -> Result )) } -fn visit_struct(index: &LineIndex, item: &Struct<'_>) -> Result { +fn visit_struct(index: &Index, item: &Struct<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::STRUCT, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, visit_fields(index, &item.fields)?, )) } -fn visit_enum(index: &LineIndex, item: &Enum<'_>) -> Result { +fn visit_enum(index: &Index, item: &Enum<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::ENUM, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, item.variants .iter() .map(|variant| visit_variant(index, variant)) @@ -59,16 +60,16 @@ fn visit_enum(index: &LineIndex, item: &Enum<'_>) -> Result { )) } -fn visit_variant(index: &LineIndex, item: &Variant<'_>) -> Result { +fn visit_variant(index: &Index, item: &Variant<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::ENUM_MEMBER, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, visit_fields(index, &item.fields)?, )) } -fn visit_fields(index: &LineIndex, item: &Fields<'_>) -> Result> { +fn visit_fields(index: &Index, item: &Fields<'_>) -> Result> { match item { Fields::Named(named) => named .iter() @@ -83,47 +84,47 @@ fn visit_fields(index: &LineIndex, item: &Fields<'_>) -> Result) -> Result { +fn visit_named_field(index: &Index, item: &NamedField<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::PROPERTY, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, vec![], )) } fn visit_unnamed_field( - index: &LineIndex, + index: &Index, item: &UnnamedField<'_>, pos: usize, ) -> Result { Ok(create_symbol( &pos.to_string(), SymbolKind::PROPERTY, - get_range(index, item.span())?, + index.get_range(item.span())?, vec![], )) } -fn visit_alias(index: &LineIndex, item: &TypeAlias<'_>) -> Result { +fn visit_alias(index: &Index, item: &TypeAlias<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::VARIABLE, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, vec![], )) } -fn visit_const(index: &LineIndex, item: &Const<'_>) -> Result { +fn visit_const(index: &Index, item: &Const<'_>) -> Result { Ok(create_symbol( item.name.get(), SymbolKind::CONSTANT, - get_range(index, item.name.span())?, + index.get_range(item.name.span())?, vec![], )) } -fn visit_import(index: &LineIndex, item: &Import<'_>) -> Result { +fn visit_import(index: &Index, item: &Import<'_>) -> Result { debug_assert!( !item.segments.is_empty(), "there should always be at least one segment" @@ -145,36 +146,16 @@ fn visit_import(index: &LineIndex, item: &Import<'_>) -> Result Ok(create_symbol( &name, SymbolKind::FILE, - get_range(index, span.into())?, + index.get_range(span)?, vec![], )) } -#[allow(clippy::cast_possible_truncation)] -fn get_range(index: &LineIndex, span: Span) -> Result { - let range = Range::from(span); - let (start, end) = index - .to_wide( - line_index::WideEncoding::Utf16, - index.line_col(TextSize::new(range.start as u32)), - ) - .zip(index.to_wide( - line_index::WideEncoding::Utf16, - index.line_col(TextSize::new(range.end as u32)), - )) - .context("missing utf-16 positions")?; - - Ok(LspRange::new( - Position::new(start.line, start.col), - Position::new(end.line, end.col), - )) -} - #[allow(deprecated)] fn create_symbol( name: &str, kind: SymbolKind, - range: LspRange, + range: lsp::Range, children: Vec, ) -> DocumentSymbol { DocumentSymbol { diff --git a/crates/mabo-lsp/src/handlers/hover.rs b/crates/mabo-lsp/src/handlers/hover.rs index c9f5d13..0ed1d28 100644 --- a/crates/mabo-lsp/src/handlers/hover.rs +++ b/crates/mabo-lsp/src/handlers/hover.rs @@ -1,37 +1,25 @@ use std::{fmt::Write, ops::Range}; -use anyhow::{Context, Result}; -use line_index::{LineIndex, TextSize, WideLineCol}; -use lsp_types::{Position, Range as LspRange}; +use anyhow::Result; +use lsp_types as lsp; use mabo_compiler::simplify::{ Const, Definition, Enum, Field, Fields, Module, ParserField, Schema, Struct, TypeAlias, Variant, }; use mabo_parser::{Span, Spanned}; +use super::index::Index; + pub fn visit_schema( - index: &LineIndex, + index: &Index, item: &Schema<'_>, - position: Position, -) -> Result> { - let position = index - .offset( - index - .to_utf8( - line_index::WideEncoding::Utf16, - WideLineCol { - line: position.line, - col: position.character, - }, - ) - .context("missing utf-16 position")?, - ) - .context("missing offset position")? - .into(); + position: lsp::Position, +) -> Result> { + let position = index.get_offset(position)?; item.definitions .iter() .find_map(|def| visit_definition(def, position)) - .map(|(text, span)| Ok((text, get_range(index, span)?))) + .map(|(text, span)| Ok((text, index.get_range(span)?))) .transpose() } @@ -146,23 +134,3 @@ fn fold_comment(comment: &[&str]) -> String { acc }) } - -#[allow(clippy::cast_possible_truncation)] -fn get_range(index: &LineIndex, span: Span) -> Result { - let range = Range::from(span); - let (start, end) = index - .to_wide( - line_index::WideEncoding::Utf16, - index.line_col(TextSize::new(range.start as u32)), - ) - .zip(index.to_wide( - line_index::WideEncoding::Utf16, - index.line_col(TextSize::new(range.end as u32)), - )) - .context("missing utf-16 positions")?; - - Ok(LspRange::new( - Position::new(start.line, start.col), - Position::new(end.line, end.col), - )) -} diff --git a/crates/mabo-lsp/src/handlers/index.rs b/crates/mabo-lsp/src/handlers/index.rs new file mode 100644 index 0000000..b2ca23e --- /dev/null +++ b/crates/mabo-lsp/src/handlers/index.rs @@ -0,0 +1,82 @@ +use std::ops::Range; + +use anyhow::{Context, Result}; +use line_index::{LineCol, LineIndex, TextSize, WideEncoding, WideLineCol}; +use lsp_types as lsp; + +pub struct Index { + index: LineIndex, + encoding: Option, +} + +impl Index { + pub fn new(index: LineIndex, encoding: &lsp::PositionEncodingKind) -> Self { + Self { + index, + encoding: match encoding.as_str() { + "utf-8" => None, + "utf-32" => Some(WideEncoding::Utf32), + _ => Some(WideEncoding::Utf16), + }, + } + } + + pub fn update(&mut self, index: LineIndex) { + self.index = index; + } + + #[allow(clippy::cast_possible_truncation)] + pub fn get_range(&self, location: impl Into>) -> Result { + let range = location.into(); + + let start = self.index.line_col(TextSize::new(range.start as u32)); + let end = self.index.line_col(TextSize::new(range.end as u32)); + + if let Some(encoding) = self.encoding { + let start = self + .index + .to_wide(encoding, start) + .context("missing start position in wide encoding")?; + + let end = self + .index + .to_wide(encoding, end) + .context("missing end position in wide encoding")?; + + return Ok(lsp::Range::new( + lsp::Position::new(start.line, start.col), + lsp::Position::new(end.line, end.col), + )); + } + + Ok(lsp::Range::new( + lsp::Position::new(start.line, start.col), + lsp::Position::new(end.line, end.col), + )) + } + + pub fn get_offset(&self, position: lsp::Position) -> Result { + let line_col = if let Some(encoding) = self.encoding { + self.index + .to_utf8( + encoding, + WideLineCol { + line: position.line, + col: position.character, + }, + ) + .context("missing utf-16 position")? + } else { + LineCol { + line: position.line, + col: position.character, + } + }; + + Ok(self + .index + .offset(line_col) + .context("missing offset position")? + .into()) + } +} diff --git a/crates/mabo-lsp/src/handlers/mod.rs b/crates/mabo-lsp/src/handlers/mod.rs index 7bea1fb..05f27a8 100644 --- a/crates/mabo-lsp/src/handlers/mod.rs +++ b/crates/mabo-lsp/src/handlers/mod.rs @@ -18,6 +18,7 @@ use lsp_types::{ }; use ropey::Rope; +use self::index::Index; use crate::{ state::{self, FileBuilder}, GlobalState, @@ -26,6 +27,7 @@ use crate::{ mod compile; mod document_symbols; mod hover; +pub mod index; mod semantic_tokens; pub fn initialize( @@ -34,6 +36,16 @@ pub fn initialize( ) -> Result { log::trace!("{params:#?}"); + // Select the most preferred position encoding defined by the client. + state.encoding = params + .capabilities + .general + .as_ref() + .and_then(|general| general.position_encodings.as_ref()) + .and_then(|encodings| encodings.first()) + .cloned() + .unwrap_or(PositionEncodingKind::UTF16); + if let Some(projects) = params .root_uri .and_then(|root| mabo_project::discover(root.path()).ok()) @@ -53,7 +65,9 @@ pub fn initialize( continue; }; - state.files.insert(uri.clone(), create_file(uri, text)); + state + .files + .insert(uri.clone(), create_file(&state.encoding, uri, text)); } } @@ -63,7 +77,7 @@ pub fn initialize( version: Some(env!("CARGO_PKG_VERSION").to_owned()), }), capabilities: ServerCapabilities { - position_encoding: Some(PositionEncodingKind::UTF16), + position_encoding: Some(state.encoding.clone()), text_document_sync: Some(TextDocumentSyncCapability::Kind( TextDocumentSyncKind::INCREMENTAL, )), @@ -133,7 +147,7 @@ pub fn did_open(state: &mut GlobalState<'_>, params: DidOpenTextDocumentParams) } else { debug!("file missing from state"); - let file = create_file(params.text_document.uri.clone(), text); + let file = create_file(&state.encoding, params.text_document.uri.clone(), text); state.files.insert(params.text_document.uri.clone(), file); &state.files[¶ms.text_document.uri] @@ -165,7 +179,7 @@ pub fn did_change(state: &mut GlobalState<'_>, mut params: DidChangeTextDocument let file = if is_full(¶ms.content_changes) { let text = params.content_changes.remove(0).text; - create_file(params.text_document.uri.clone(), text) + create_file(&state.encoding, params.text_document.uri.clone(), text) } else { let Some(file) = state.files.remove(¶ms.text_document.uri) else { warn!("missing state for changed file"); @@ -299,44 +313,24 @@ pub fn did_change_configuration( } } -fn convert_range(index: &LineIndex, range: Option) -> Result { +fn convert_range(index: &Index, range: Option) -> Result { let range = range.context("incremental change misses range")?; let start = index - .offset( - index - .to_utf8( - line_index::WideEncoding::Utf16, - line_index::WideLineCol { - line: range.start.line, - col: range.start.character, - }, - ) - .context("failed to convert start position to utf-8")?, - ) + .get_offset(range.start) .context("failed to convert start position to byte offset")?; let end = index - .offset( - index - .to_utf8( - line_index::WideEncoding::Utf16, - line_index::WideLineCol { - line: range.end.line, - col: range.end.character, - }, - ) - .context("failed to convert end position to utf-8")?, - ) + .get_offset(range.end) .context("failed to convert end position to byte offset")?; - Ok(TextRange::new(start, end)) + Ok(TextRange::new(start.try_into()?, end.try_into()?)) } -fn create_file(uri: Url, text: String) -> state::File { +fn create_file(encoding: &PositionEncodingKind, uri: Url, text: String) -> state::File { FileBuilder { rope: Rope::from_str(&text), - index: LineIndex::new(&text), + index: Index::new(LineIndex::new(&text), encoding), content: text, schema_builder: |index, schema| compile::compile(uri, schema, index), simplified_builder: compile::simplify, @@ -344,19 +338,17 @@ fn create_file(uri: Url, text: String) -> state::File { .build() } -fn update_file( - uri: Url, - file: state::File, - update: impl FnOnce(&mut Rope, &LineIndex), -) -> state::File { +fn update_file(uri: Url, file: state::File, update: impl FnOnce(&mut Rope, &Index)) -> state::File { let mut heads = file.into_heads(); update(&mut heads.rope, &heads.index); let text = String::from(&heads.rope); + heads.index.update(LineIndex::new(&text)); + FileBuilder { rope: heads.rope, - index: LineIndex::new(&text), + index: heads.index, content: text, schema_builder: |index, schema| compile::compile(uri, schema, index), simplified_builder: compile::simplify, diff --git a/crates/mabo-lsp/src/handlers/semantic_tokens.rs b/crates/mabo-lsp/src/handlers/semantic_tokens.rs index 1d8480c..80af690 100644 --- a/crates/mabo-lsp/src/handlers/semantic_tokens.rs +++ b/crates/mabo-lsp/src/handlers/semantic_tokens.rs @@ -1,7 +1,4 @@ -use std::ops::Range; - -use anyhow::{ensure, Context, Result}; -use line_index::{LineIndex, TextSize, WideLineCol}; +use anyhow::{ensure, Result}; use lsp_types::{SemanticToken, SemanticTokenModifier, SemanticTokenType}; use mabo_parser::{ Comment, Const, DataType, Definition, Enum, Fields, Generics, Id, Literal, LiteralValue, @@ -9,6 +6,7 @@ use mabo_parser::{ }; pub(crate) use self::{modifiers::TOKEN_MODIFIERS, types::TOKEN_TYPES}; +use super::index::Index; macro_rules! define_semantic_token_types { ( @@ -115,50 +113,45 @@ fn token_modifier_bitset(modifiers: &[SemanticTokenModifier]) -> u32 { } pub struct Visitor<'a> { - index: &'a LineIndex, + index: &'a Index, tokens: Vec, - delta: WideLineCol, + delta: lsp_types::Position, } impl<'a> Visitor<'a> { - pub fn new(index: &'a LineIndex) -> Self { + pub fn new(index: &'a Index) -> Self { Self { index, tokens: Vec::new(), - delta: WideLineCol { line: 0, col: 0 }, + delta: lsp_types::Position { + line: 0, + character: 0, + }, } } #[allow(clippy::cast_possible_truncation)] - fn get_range(&self, span: Span) -> Result<(WideLineCol, WideLineCol)> { - let range = Range::from(span); - let (start, end) = self - .index - .to_wide( - line_index::WideEncoding::Utf16, - self.index.line_col(TextSize::new(range.start as u32)), - ) - .zip(self.index.to_wide( - line_index::WideEncoding::Utf16, - self.index.line_col(TextSize::new(range.end as u32)), - )) - .context("missing utf-16 positions")?; - - ensure!(start.line == end.line, "encountered a multi-line span"); - - Ok((start, end)) + fn get_range(&self, span: Span) -> Result { + let range = self.index.get_range(span)?; + + ensure!( + range.start.line == range.end.line, + "encountered a multi-line span" + ); + + Ok(range) } - fn lsl(&self, start: WideLineCol, end: WideLineCol) -> (u32, u32, u32) { + fn lsl(&self, start: lsp_types::Position, end: lsp_types::Position) -> (u32, u32, u32) { ( start.line - self.delta.line, - start.col + start.character - if self.delta.line == start.line { - self.delta.col + self.delta.character } else { 0 }, - end.col - start.col, + end.character - start.character, ) } @@ -168,8 +161,8 @@ impl<'a> Visitor<'a> { token_type: &SemanticTokenType, token_modifiers: &[SemanticTokenModifier], ) -> Result<()> { - let (start, end) = self.get_range(span.span())?; - let (delta_line, delta_start, length) = self.lsl(start, end); + let range = self.get_range(span.span())?; + let (delta_line, delta_start, length) = self.lsl(range.start, range.end); self.tokens.push(SemanticToken { delta_line, @@ -178,9 +171,9 @@ impl<'a> Visitor<'a> { token_type: token_type_pos(token_type), token_modifiers_bitset: token_modifier_bitset(token_modifiers), }); - self.delta = WideLineCol { - line: start.line, - col: start.col, + self.delta = lsp_types::Position { + line: range.start.line, + character: range.start.character, }; Ok(()) diff --git a/crates/mabo-lsp/src/main.rs b/crates/mabo-lsp/src/main.rs index f05cdf2..756aacd 100644 --- a/crates/mabo-lsp/src/main.rs +++ b/crates/mabo-lsp/src/main.rs @@ -18,10 +18,8 @@ use lsp_types::{ }, DocumentSymbol, InitializeParams, SemanticTokens, }; -use rustc_hash::FxHashMap; -use self::{cli::Cli, client::Client}; -use crate::state::GlobalState; +use crate::{cli::Cli, state::GlobalState}; mod cli; mod client; @@ -44,11 +42,7 @@ fn main() -> Result<()> { bail!("no connection method provided") }; - let mut state = GlobalState { - client: Client::new(&connection), - files: FxHashMap::default(), - settings: config::Global::default(), - }; + let mut state = GlobalState::new(&connection); let (id, params) = connection.initialize_start()?; let init_params = serde_json::from_value::(params)?; diff --git a/crates/mabo-lsp/src/state.rs b/crates/mabo-lsp/src/state.rs index 702b654..4a342f0 100644 --- a/crates/mabo-lsp/src/state.rs +++ b/crates/mabo-lsp/src/state.rs @@ -1,17 +1,18 @@ use anyhow::{ensure, Context, Result}; -use line_index::LineIndex; use log::{as_debug, debug}; -use lsp_types::{ConfigurationItem, Diagnostic, Url}; +use lsp_server::Connection; +use lsp_types::{ConfigurationItem, Diagnostic, PositionEncodingKind, Url}; use mabo_parser::Schema; use ouroboros::self_referencing; use ropey::Rope; use rustc_hash::FxHashMap; -use crate::{client::Client, config}; +use crate::{client::Client, config, handlers::index::Index}; #[allow(clippy::module_name_repetitions)] pub struct GlobalState<'a> { pub client: Client<'a>, + pub encoding: PositionEncodingKind, pub files: FxHashMap, pub settings: config::Global, } @@ -19,7 +20,7 @@ pub struct GlobalState<'a> { #[self_referencing(pub_extras)] pub struct File { rope: Rope, - pub index: LineIndex, + pub index: Index, pub content: String, #[borrows(index, content)] #[covariant] @@ -29,7 +30,16 @@ pub struct File { pub simplified: Result, &'this Diagnostic>, } -impl GlobalState<'_> { +impl<'a> GlobalState<'a> { + pub fn new(connection: &'a Connection) -> Self { + Self { + client: Client::new(connection), + encoding: PositionEncodingKind::UTF16, + files: FxHashMap::default(), + settings: config::Global::default(), + } + } + pub fn reload_settings(&mut self) -> Result<()> { let mut settings = self .client