fix: converts out of bounds offsets again (#115)

* fix: converts out of bounds offsets again

* fix: wrong length calculation

* dev: accept hash
This commit is contained in:
Myriad-Dreamin 2024-03-29 02:20:12 +08:00 committed by GitHub
parent 5f27135419
commit 3a0e8e3d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 5 deletions

View file

@ -123,7 +123,10 @@ typst-pdf = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tin
# typst = { path = "../typst/crates/typst" } # typst = { path = "../typst/crates/typst" }
# typst-ide = { path = "../typst/crates/typst-ide" } # 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-pdf = { path = "../typst/crates/typst-pdf" }
# typst-render = { path = "../typst/crates/typst-render" }
# typst-syntax = { path = "../typst/crates/typst-syntax" } # typst-syntax = { path = "../typst/crates/typst-syntax" }
# typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" } # typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" }

View file

@ -74,8 +74,21 @@ pub mod lsp_to_typst {
lsp_position_encoding: LspPositionEncoding, lsp_position_encoding: LspPositionEncoding,
typst_source: &Source, typst_source: &Source,
) -> Option<TypstOffset> { ) -> Option<TypstOffset> {
if lsp_position.line >= typst_source.len_lines() as u32 { let lines = typst_source.len_lines() as u32;
if lsp_position.line > typst_source.len_lines() as u32 || lsp_position.character > 0 { 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::<usize>()
}
};
lsp_position.character as usize >= len
})
{
if lsp_position.line > lines || lsp_position.character > 0 {
log::warn!( log::warn!(
"LSP position is out of bounds: {:?}, while only {:?} lines and {:?} characters at the end.", "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), 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)] #[cfg(test)]
mod test { mod test {
use lsp_types::Position;
use typst::syntax::Source; use typst::syntax::Source;
use crate::{lsp_to_typst, PositionEncoding}; use crate::{lsp_to_typst, PositionEncoding};
@ -332,6 +346,53 @@ mod test {
assert_eq!(res, 22..22); 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] #[test]
fn utf16_position_to_utf8_offset() { fn utf16_position_to_utf8_offset() {
let source = Source::detached(ENCODING_TEST_STRING); let source = Source::detached(ENCODING_TEST_STRING);

View file

@ -139,8 +139,16 @@ fn e2e() {
std::env::set_var("RUST_BACKTRACE", "full"); std::env::set_var("RUST_BACKTRACE", "full");
let cwd = find_git_root().unwrap(); let cwd = find_git_root().unwrap();
// assert!(exec("cargo", ["build", "--release", "--bin", if cfg!(target_os = "...") {
// "tinymist"]).success()); 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"); let root = cwd.join("target/e2e/tinymist");
gen(&root.join("vscode"), |srv| { gen(&root.join("vscode"), |srv| {
use lsp_types::notification::*; use lsp_types::notification::*;
@ -347,7 +355,7 @@ fn e2e() {
std::fs::write(root.join("vscode/result_sorted.json"), c).unwrap(); std::fs::write(root.join("vscode/result_sorted.json"), c).unwrap();
let hash = format!("siphash128_13:{:x}", hash); 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); struct StableHash<'a>(&'a Value);