From 3a0e8e3d26ac02299f4f52c70cc4385b96a95fb3 Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Fri, 29 Mar 2024 02:20:12 +0800 Subject: [PATCH] fix: converts out of bounds offsets again (#115) * fix: converts out of bounds offsets again * fix: wrong length calculation * dev: accept hash --- Cargo.toml | 3 + .../tinymist-query/src/lsp_typst_boundary.rs | 65 ++++++++++++++++++- tests/e2e/main.rs | 14 +++- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c653fcc..3662b75f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,10 @@ typst-pdf = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tin # typst = { path = "../typst/crates/typst" } # typst-ide = { path = "../typst/crates/typst-ide" } +# typst-timing = { path = "../typst/crates/typst-timing" } +# typst-svg = { path = "../typst/crates/typst-svg" } # typst-pdf = { path = "../typst/crates/typst-pdf" } +# typst-render = { path = "../typst/crates/typst-render" } # typst-syntax = { path = "../typst/crates/typst-syntax" } # typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" } diff --git a/crates/tinymist-query/src/lsp_typst_boundary.rs b/crates/tinymist-query/src/lsp_typst_boundary.rs index 9614a772..6b872725 100644 --- a/crates/tinymist-query/src/lsp_typst_boundary.rs +++ b/crates/tinymist-query/src/lsp_typst_boundary.rs @@ -74,8 +74,21 @@ pub mod lsp_to_typst { lsp_position_encoding: LspPositionEncoding, typst_source: &Source, ) -> Option { - if lsp_position.line >= typst_source.len_lines() as u32 { - if lsp_position.line > typst_source.len_lines() as u32 || lsp_position.character > 0 { + let lines = typst_source.len_lines() as u32; + if lsp_position.line >= lines + || (lsp_position.line + 1 == lines && { + let last_line_offset = typst_source.line_to_byte(lines as usize - 1)?; + let last_line_chars = &typst_source.text()[last_line_offset..]; + let len = match lsp_position_encoding { + LspPositionEncoding::Utf8 => last_line_chars.len(), + LspPositionEncoding::Utf16 => { + last_line_chars.chars().map(char::len_utf16).sum::() + } + }; + lsp_position.character as usize >= len + }) + { + if lsp_position.line > lines || lsp_position.character > 0 { log::warn!( "LSP position is out of bounds: {:?}, while only {:?} lines and {:?} characters at the end.", lsp_position, typst_source.len_lines(), typst_source.line_to_range(typst_source.len_lines() - 1), @@ -306,6 +319,7 @@ pub mod typst_to_lsp { #[cfg(test)] mod test { + use lsp_types::Position; use typst::syntax::Source; use crate::{lsp_to_typst, PositionEncoding}; @@ -332,6 +346,53 @@ mod test { assert_eq!(res, 22..22); } + #[test] + fn issue_14_invalid_range_2() { + let source = Source::detached( + r"#let f(a) = { + a +} +", + ); + let rng = LspRange { + start: LspPosition { + line: 2, + character: 1, + }, + // EOF + end: LspPosition { + line: 3, + character: 0, + }, + }; + let res = lsp_to_typst::range(rng, PositionEncoding::Utf16, &source).unwrap(); + assert_eq!(res, 19..source.len_bytes()); + // EOF + let rng = LspRange { + start: LspPosition { + line: 3, + character: 1, + }, + end: LspPosition { + line: 4, + character: 0, + }, + }; + let res = lsp_to_typst::range(rng, PositionEncoding::Utf16, &source).unwrap(); + assert_eq!(res, source.len_bytes()..source.len_bytes()); + + for line in 0..=5 { + for character in 0..2 { + let off = lsp_to_typst::position( + Position { line, character }, + PositionEncoding::Utf16, + &source, + ); + assert!(off.is_some(), "line: {line}, character: {character}"); + } + } + } + #[test] fn utf16_position_to_utf8_offset() { let source = Source::detached(ENCODING_TEST_STRING); diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index f6a12da9..57944085 100644 --- a/tests/e2e/main.rs +++ b/tests/e2e/main.rs @@ -139,8 +139,16 @@ fn e2e() { std::env::set_var("RUST_BACKTRACE", "full"); let cwd = find_git_root().unwrap(); - // assert!(exec("cargo", ["build", "--release", "--bin", - // "tinymist"]).success()); + if cfg!(target_os = "...") { + let w = Command::new("cargo") + .args(["build", "--release", "--bin", "tinymist"]) + .status(); + assert!(handle_io(w).success()); + handle_io(std::fs::copy( + cwd.join("target/release/tinymist.exe"), + cwd.join("editors/vscode/out/tinymist.exe"), + )); + } let root = cwd.join("target/e2e/tinymist"); gen(&root.join("vscode"), |srv| { use lsp_types::notification::*; @@ -347,7 +355,7 @@ fn e2e() { std::fs::write(root.join("vscode/result_sorted.json"), c).unwrap(); let hash = format!("siphash128_13:{:x}", hash); - insta::assert_snapshot!(hash, @"siphash128_13:3ca43097c9772ff12a1918d876cbf6ad"); + insta::assert_snapshot!(hash, @"siphash128_13:1e0ee515d35c16937e02684a605379bb"); } struct StableHash<'a>(&'a Value);