-
Notifications
You must be signed in to change notification settings - Fork 29
Add ArkDb, ArkFile, and tree_sitter() query for legacy handlers
#1263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1794ab3
6af4dab
4b9ea73
d7bd8a5
c5255f0
ab4ff95
35c6e37
8c076f7
f2a6a11
d422fdd
1584fee
3b6d87f
1e62c30
1cdf7bb
ff4648a
283a875
5b093d8
8578846
8b89d4f
0e8e3d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| // | ||
| // ark_file.rs | ||
| // | ||
| // Copyright (C) 2026 Posit Software, PBC. All rights reserved. | ||
| // | ||
| // | ||
|
|
||
| use aether_lsp_utils::proto::from_proto; | ||
| use aether_lsp_utils::proto::to_proto; | ||
| use aether_lsp_utils::proto::PositionEncoding; | ||
| use oak_db::File; | ||
| use tower_lsp::lsp_types; | ||
| use url::Url; | ||
|
|
||
| use crate::lsp::config::DocumentConfig; | ||
| use crate::lsp::db::ArkDb; | ||
| use crate::lsp::db::FileArkExt; | ||
|
|
||
| /// Editor-managed buffer state, paired with its `oak_db::File`. | ||
| /// | ||
| /// `ArkFile` and `OakDatabase` are sibling fields on `WorldState`, so an | ||
| /// `ArkFile` cannot hold a reference to the database. That's why the methods | ||
| /// below take `db` as an argument instead of storing a reference, which is the | ||
| /// Salsa convention anyway. | ||
| #[derive(Debug)] | ||
| pub(crate) struct ArkFile { | ||
| pub(crate) file: File, | ||
| pub(crate) version: Option<i32>, | ||
| pub(crate) config: DocumentConfig, | ||
| pub(crate) url: Url, | ||
| pub(crate) encoding: PositionEncoding, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hoping this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
|
|
||
| impl ArkFile { | ||
| pub(crate) fn tree_sitter<'db>(&self, db: &'db dyn ArkDb) -> &'db tree_sitter::Tree { | ||
| self.file.tree_sitter(db) | ||
| } | ||
|
|
||
| pub(crate) fn line_index<'db>(&self, db: &'db dyn ArkDb) -> &'db biome_line_index::LineIndex { | ||
| self.file.line_index(db) | ||
| } | ||
|
|
||
| pub(crate) fn contents<'db>(&self, db: &'db dyn ArkDb) -> &'db str { | ||
| self.file.contents(db).as_str() | ||
| } | ||
|
|
||
| pub(crate) fn get_line<'db>(&self, db: &'db dyn ArkDb, line: usize) -> Option<&'db str> { | ||
| let line_index = self.line_index(db); | ||
| let contents = self.contents(db); | ||
|
|
||
| let Some(line_start) = line_index.newlines.get(line) else { | ||
| // Forcing a full capture so we can learn the situations in which this occurs | ||
| log::error!( | ||
| "Requesting line {line} but only {n} lines exist.\n\nContents:\n{contents}\n\nBacktrace:\n{trace}", | ||
| n = line_index.len(), | ||
| line = line + 1, | ||
| trace = std::backtrace::Backtrace::force_capture(), | ||
| ); | ||
| return None; | ||
| }; | ||
|
|
||
| let line_end = line_index | ||
| .newlines | ||
| .get(line + 1) | ||
| .copied() | ||
| // if `line` is last, extract text until end of buffer | ||
| .unwrap_or_else(|| (contents.len() as u32).into()); | ||
|
|
||
| let line_start_byte: usize = line_start.to_owned().into(); | ||
| let line_end_byte: usize = line_end.into(); | ||
|
|
||
| contents.get(line_start_byte..line_end_byte) | ||
| } | ||
|
|
||
| pub(crate) fn tree_sitter_point_from_lsp_position( | ||
| &self, | ||
| db: &dyn ArkDb, | ||
| position: lsp_types::Position, | ||
| ) -> anyhow::Result<tree_sitter::Point> { | ||
| let line_col = | ||
| from_proto::line_col_from_position(position, self.line_index(db), self.encoding); | ||
| Ok(tree_sitter::Point::new( | ||
| line_col.line as usize, | ||
| line_col.col as usize, | ||
| )) | ||
| } | ||
|
|
||
| pub(crate) fn lsp_position_from_tree_sitter_point( | ||
| &self, | ||
| db: &dyn ArkDb, | ||
| point: tree_sitter::Point, | ||
| ) -> anyhow::Result<lsp_types::Position> { | ||
| let line_col = biome_line_index::LineCol { | ||
| line: point.row as u32, | ||
| col: point.column as u32, | ||
| }; | ||
| to_proto::position_from_line_col(line_col, self.line_index(db), self.encoding) | ||
| } | ||
|
|
||
| pub(crate) fn lsp_range_from_tree_sitter_range( | ||
| &self, | ||
| db: &dyn ArkDb, | ||
| range: tree_sitter::Range, | ||
| ) -> anyhow::Result<lsp_types::Range> { | ||
| let start = self.lsp_position_from_tree_sitter_point(db, range.start_point)?; | ||
| let end = self.lsp_position_from_tree_sitter_point(db, range.end_point)?; | ||
| Ok(lsp_types::Range::new(start, end)) | ||
| } | ||
|
|
||
| pub(crate) fn tree_sitter_range_from_lsp_range( | ||
| &self, | ||
| db: &dyn ArkDb, | ||
| range: lsp_types::Range, | ||
| ) -> anyhow::Result<tree_sitter::Range> { | ||
| let start_point = self.tree_sitter_point_from_lsp_position(db, range.start)?; | ||
| let end_point = self.tree_sitter_point_from_lsp_position(db, range.end)?; | ||
|
|
||
| let text_range = from_proto::text_range(range, self.line_index(db), self.encoding)?; | ||
|
|
||
| Ok(tree_sitter::Range { | ||
| start_byte: text_range.start().into(), | ||
| end_byte: text_range.end().into(), | ||
| start_point, | ||
| end_point, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| pub(crate) fn test_ark_file(code: &str) -> (oak_db::OakDatabase, ArkFile) { | ||
| use aether_path::FilePath; | ||
|
|
||
| let db = oak_db::OakDatabase::new(); | ||
| let url = Url::parse("file:///test.R").unwrap(); | ||
| let key = FilePath::from_url(&url); | ||
| let file = ArkFile { | ||
| file: File::new(&db, key, code.to_string(), None), | ||
| version: None, | ||
| config: DocumentConfig::default(), | ||
| url, | ||
| encoding: PositionEncoding::Wide(biome_line_index::WideEncoding::Utf16), | ||
| }; | ||
| (db, file) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,10 @@ use tower_lsp::lsp_types; | |
| use tree_sitter::Range; | ||
| use url::Url; | ||
|
|
||
| use crate::lsp::ark_file::ArkFile; | ||
| use crate::lsp::capabilities::Capabilities; | ||
| use crate::lsp::code_action::roxygen::roxygen_documentation; | ||
| use crate::lsp::document::Document; | ||
| use crate::lsp::db::ArkDb; | ||
|
|
||
| mod roxygen; | ||
|
|
||
|
|
@@ -25,14 +26,14 @@ pub(crate) struct CodeActions { | |
| } | ||
|
|
||
| pub(crate) fn code_actions( | ||
| uri: &Url, | ||
| document: &Document, | ||
| db: &dyn ArkDb, | ||
| file: &ArkFile, | ||
| range: Range, | ||
| capabilities: &Capabilities, | ||
| ) -> lsp_types::CodeActionResponse { | ||
| let mut actions = CodeActions::new(); | ||
|
|
||
| roxygen_documentation(&mut actions, uri, document, range, capabilities); | ||
| roxygen_documentation(db, file, &mut actions, range, capabilities); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did like having
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense too, but context params go first by convention. |
||
|
|
||
| actions.into_response() | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.