Skip to content

Conversation

@DavisVaughan
Copy link
Contributor

@DavisVaughan DavisVaughan commented Jun 4, 2025

Summary

Hiya Biome team,

We used the Biome formatter infrastructure to create Air, an R formatter. The Biome infra has been fantastic for us, so thank you all so much for your great work!

We have our own LSP server, and we want to move it from using tower-lsp -> lsp-server, and from tower_lsp::lsp_types::* -> lsp_types::* (i.e. using lsp-types directly, not reexported by tower-lsp). We tried doing this, but got roadblocked by our usage of biome-lsp-converters.

biome-lsp-converters provides two things:

  • The LSP server agnostic LineIndex type, which is extremely useful for conversion between byte offset and line/column position (the implementation of this is just 🔥)
  • A few LSP server specific conversion utilities (tied to tower_lsp::lsp_types::*), like:
    • from_proto::offset()
    • from_proto::text_range()
    • to_proto::position()
    • to_proto::range()

We really want to be able to use your great LineIndex type for conversions, but we don't want the tower-lsp (and tokio) dependency that comes with that. In biome-lsp-converters, you import tower-lsp just to be able to access their tower_lsp::lsp_types::* reexports, but Rust doesn't consider those reexports compatible with lsp_types::* itself.

Would you consider this PR that splits out the LineIndex type into its own biome_line_index crate? It would be nice for us to be able to depend on this lighter weight crate instead, and LineIndex seems like an extremely handy little utility for language servers in particular, so other people may also find it useful (we will probably also use it in Ark, which is more of a full blown R language server and a jupyter kernel).

I'm already using this biome_line_index crate here as a POC, and it worked as expected posit-dev/air#354

I'm not sure if you would want biome_lsp_converters to reexport everything from biome_line_index or not. I did not do that for now, and instead updated all the use declarations in your biome_lsp crate. Let me know if that's not what you want (for example, if you don't want a breaking change in the biome_lsp_converters API).

I have not changed any of the actual implementation of LineIndex, the only things that have changed are:

  • The biome_rowan dep was swapped for biome_text_size, because it is slimmer
  • The tests in biome_line_index are the old tests, but now use WideLineCol instead of lsp_types::Position
  • The tests in biome_lsp_converters were mostly kept, but I removed ones that were explicitly about just the LineIndex details, since they are duplicated in biome_line_index

Test Plan

Existing tests were maintained

@github-actions github-actions bot added the A-LSP Area: language server protocol label Jun 4, 2025
Comment on lines +72 to +82
macro_rules! check_conversion {
($line_index:ident : $wide_line_col:expr => $text_size:expr ) => {
let encoding = WideEncoding::Utf16;

let line_col = $line_index.to_utf8(encoding, $wide_line_col);
let offset = $line_index.offset(line_col);
assert_eq!(offset, Some($text_size));

let line_col = $line_index.line_col(offset.unwrap());
let wide_line_col = $line_index.to_wide(encoding, line_col.unwrap());
assert_eq!(wide_line_col, Some($wide_line_col));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to use PositionEncoding::Wide(WideEncoding::Utf16), offset(), and position(), but we don't have access to those here, so I've had to tweak the tests to have the same effect. I think they are spiritually the same, but test at a slightly lower level now.

The original tests with the LSP types still exist in biome_lsp_converters

Comment on lines -130 to -136
#[test]
fn out_of_bounds_line() {
let line_index = LineIndex::new("abcde\nfghij\n");

let offset = line_index.offset(LineCol { line: 5, col: 0 });
assert!(offset.is_none());
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lives in biome_line_index because it specifically tests LineIndex, not an LSP related thing

Comment on lines -152 to -155
#[ignore]
#[test]
fn test_every_chars() {
let text: String = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lives in biome_line_index because it specifically tests LineIndex, not an LSP related thing

}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum WideEncoding {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note how you no longer have

biome_lsp_converters::WideEncoding
biome_lsp_converters::line_index::LineIndex

instead you have

biome_line_index::WideEncoding
biome_line_index::LineIndex

I'm unsure of how strict you all are about breaking changes like this one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't guarantee SemVer of our crates because we're a moving target, so I think it's fine to change things like this :)

@DavisVaughan DavisVaughan changed the title Extract out a biome_line_index crate refactor: Extract out a biome_line_index crate Jun 4, 2025
@DavisVaughan DavisVaughan changed the title refactor: Extract out a biome_line_index crate refactor: extract out a biome_line_index crate Jun 4, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented Jun 4, 2025

CodSpeed Performance Report

Merging #6222 will not alter performance

Comparing DavisVaughan:feature/line-index (afe43a8) with main (d42c38c)

Summary

✅ 97 untouched benchmarks

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR and the kind words!

This looks totally fine for us, but you'll have to wait for the merge a bit. We're about to release 2.0, so we trying to minimise the impact right now. We'll open main again soon enough 🤞

@arendjr arendjr added this to the Biome 2.1 milestone Jun 23, 2025
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @DavisVaughan, I think we can merge this PR whenever you want. @arendjr what do you think? There aren't any minor changes inside @biomejs/biome, and we don't usually guarantee semver of our crates

}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum WideEncoding {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't guarantee SemVer of our crates because we're a moving target, so I think it's fine to change things like this :)

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed!

@arendjr arendjr removed this from the Biome 2.1 milestone Jun 29, 2025
@ematipico ematipico merged commit c13fc60 into biomejs:main Jun 29, 2025
14 of 16 checks passed
@DavisVaughan
Copy link
Contributor Author

Thank you @ematipico and @arendjr!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LSP Area: language server protocol

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants