Skip to content

Commit f01caad

Browse files
committed
Implement LibraryDefinitions backed by PackageCache
- Stored in `WorldState` - Used in `goto_definition()` - Split out `oak_library/` from `oak_package/` so that `oak_package` stays very lightweight - Split out `oak_layers/` from `oak_index/` so that `oak_index` is purely about the `SemanticIndex`, because `oak_layers` needs the heavier package cache utilities
1 parent 5d9785c commit f01caad

31 files changed

Lines changed: 1065 additions & 419 deletions

Cargo.lock

Lines changed: 38 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ async-trait = "0.1.66"
3838
base64 = "0.21.0"
3939
biome_line_index = { git = "https://github.com/lionel-/biome", rev = "41d799cfa4cedd25625fc3f6bd7898532873f051" }
4040
biome_rowan = { git = "https://github.com/lionel-/biome", rev = "41d799cfa4cedd25625fc3f6bd7898532873f051" }
41+
biome_text_size = { git = "https://github.com/lionel-/biome", rev = "41d799cfa4cedd25625fc3f6bd7898532873f051" }
4142
blake3 = "1.8.2"
4243
bus = "2.3.0"
4344
cc = "1.1.22"
@@ -76,6 +77,8 @@ oak_fs = { path = "crates/oak_fs" }
7677
oak_ide = { path = "crates/oak_ide" }
7778
oak_index = { path = "crates/oak_index" }
7879
oak_index_vec = { path = "crates/oak_index_vec" }
80+
oak_layers = { path = "crates/oak_layers" }
81+
oak_library = { path = "crates/oak_library" }
7982
oak_package = { path = "crates/oak_package" }
8083
oak_r_process = { path = "crates/oak_r_process" }
8184
oak_sources = { path = "crates/oak_sources" }

crates/ark/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ notify.workspace = true
4747
oak_core.workspace = true
4848
oak_ide.workspace = true
4949
oak_index.workspace = true
50+
oak_layers.workspace = true
51+
oak_library.workspace = true
5052
oak_package.workspace = true
5153
once_cell.workspace = true
5254
regex.workspace = true
@@ -80,7 +82,7 @@ yaml-rust.workspace = true
8082
ark_test.workspace = true
8183
assert_matches.workspace = true
8284
insta.workspace = true
83-
oak_package = { workspace = true, features = ["testing"] }
85+
oak_library = { workspace = true, features = ["testing"] }
8486
stdext = { workspace = true, features = ["testing"] }
8587
tempfile.workspace = true
8688

crates/ark/src/lsp/diagnostics.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use anyhow::bail;
1414
use anyhow::Result;
1515
use harp::syntax::is_valid_symbol;
1616
use harp::syntax::sym_quote_invalid;
17-
use oak_package::library::Library;
18-
use oak_package::package::Package;
17+
use oak_library::library::Library;
18+
use oak_library::package::Package;
1919
use stdext::*;
2020
use tower_lsp::lsp_types::Diagnostic;
2121
use tower_lsp::lsp_types::DiagnosticSeverity;
@@ -169,14 +169,14 @@ pub(crate) fn generate_diagnostics(
169169
// If this is a package, add imported symbols to workspace
170170
if let Some(SourceRoot::Package(root)) = &state.root {
171171
// Add symbols from `importFrom()` directives
172-
for import in &root.namespace.imports {
172+
for import in &root.namespace().imports {
173173
context.workspace_symbols.insert(import.name.clone());
174174
}
175175

176176
// Add symbols from `import()` directives
177-
for package_import in &root.namespace.package_imports {
177+
for package_import in &root.namespace().package_imports {
178178
if let Some(pkg) = state.library.get(package_import) {
179-
for export in &pkg.namespace.exports {
179+
for export in &pkg.namespace().exports {
180180
context.workspace_symbols.insert(export.clone());
181181
}
182182
}
@@ -193,7 +193,7 @@ pub(crate) fn generate_diagnostics(
193193
// test files setup.
194194
if testthat {
195195
if let Some(pkg) = state.library.get("testthat") {
196-
for export in &pkg.namespace.exports {
196+
for export in &pkg.namespace().exports {
197197
context.workspace_symbols.insert(export.clone());
198198
}
199199
}
@@ -882,14 +882,14 @@ fn handle_package_attach_call(node: Node, context: &mut DiagnosticContext) -> an
882882
let package = insert_package_exports(package_name, attach_pos, context)?;
883883

884884
// Also attach packages from `Depends` field
885-
for package_name in package.description.depends.iter() {
885+
for package_name in package.description().depends.iter() {
886886
insert_package_exports(package_name, attach_pos, context)?;
887887
}
888888

889889
// Special handling for the tidyverse and tidymodels packages. Hard-coded
890890
// for now but in the future, this should probably be expressed as a
891891
// `DESCRIPTION` field like `Config/Needs/attach`.
892-
let attach_field = match package.description.name.as_str() {
892+
let attach_field = match package.description().name.as_str() {
893893
// https://github.com/tidyverse/tidyverse/blob/0231aafb/R/attach.R#L1
894894
"tidyverse" => {
895895
vec![
@@ -949,7 +949,7 @@ fn insert_package_exports(
949949
.library_symbols
950950
.entry(attach_pos)
951951
.or_default()
952-
.extend(package.exported_symbols.iter().cloned());
952+
.extend(package.exported_symbols().clone().into_vec());
953953

954954
Ok(package)
955955
}
@@ -1132,12 +1132,13 @@ mod tests {
11321132
use std::path::PathBuf;
11331133

11341134
use harp::eval::RParseEvalOptions;
1135-
use oak_package::library::Library;
1136-
use oak_package::package::Package;
1135+
use oak_library::library::Library;
1136+
use oak_library::package::Package;
11371137
use oak_package::package_description::Dcf;
11381138
use oak_package::package_description::Description;
11391139
use oak_package::package_namespace::Namespace;
11401140
use once_cell::sync::Lazy;
1141+
use stdext::SortedVec;
11411142
use tower_lsp::lsp_types;
11421143
use tower_lsp::lsp_types::Position;
11431144

@@ -1638,7 +1639,7 @@ foo
16381639
r_task(|| {
16391640
// `mockpkg` exports `foo` and `bar`
16401641
let namespace = Namespace {
1641-
exports: vec!["foo".to_string(), "bar".to_string()],
1642+
exports: SortedVec::from_vec(vec!["foo".to_string(), "bar".to_string()]),
16421643
imports: vec![],
16431644
package_imports: vec![],
16441645
};
@@ -1736,7 +1737,7 @@ foo
17361737
r_task(|| {
17371738
// pkg1 exports `foo` and `bar`
17381739
let namespace1 = Namespace {
1739-
exports: vec!["foo".to_string(), "bar".to_string()],
1740+
exports: SortedVec::from_vec(vec!["foo".to_string(), "bar".to_string()]),
17401741
imports: vec![],
17411742
package_imports: vec![],
17421743
};
@@ -1753,7 +1754,7 @@ foo
17531754

17541755
// pkg2 exports `bar` and `baz`
17551756
let namespace2 = Namespace {
1756-
exports: vec!["bar".to_string(), "baz".to_string()],
1757+
exports: SortedVec::from_vec(vec!["bar".to_string(), "baz".to_string()]),
17571758
imports: vec![],
17581759
package_imports: vec![],
17591760
};
@@ -1812,7 +1813,7 @@ foo
18121813
r_task(|| {
18131814
// `pkg` exports `foo` and `bar`
18141815
let namespace = Namespace {
1815-
exports: vec!["foo".to_string(), "bar".to_string()],
1816+
exports: SortedVec::from_vec(vec!["foo".to_string(), "bar".to_string()]),
18161817
imports: vec![],
18171818
package_imports: vec![],
18181819
};
@@ -1853,7 +1854,7 @@ foo
18531854
#[test]
18541855
fn test_penguins_symbol_no_diagnostic() {
18551856
r_task(|| {
1856-
let palmerpenguins_dir = oak_package::package::temp_palmerpenguin();
1857+
let palmerpenguins_dir = oak_library::package::temp_palmerpenguin();
18571858
let palmerpenguins_pkg = Package::load_from_folder(palmerpenguins_dir.path())
18581859
.unwrap()
18591860
.unwrap();

crates/ark/src/lsp/diagnostics_syntax.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ fn new_syntax_diagnostic(
427427

428428
#[cfg(test)]
429429
mod tests {
430-
use oak_package::library::Library;
430+
use oak_library::library::Library;
431431
use tower_lsp::lsp_types::Diagnostic;
432432
use tower_lsp::lsp_types::Position;
433433

crates/ark/src/lsp/goto_definition.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub(crate) fn goto_definition(
3333
&index,
3434
&state.external_scope(&uri),
3535
&state.library,
36+
state.library_definitions.as_ref(),
3637
);
3738

3839
if targets.is_empty() {
@@ -84,8 +85,8 @@ mod tests {
8485
use std::process::Command;
8586

8687
use assert_matches::assert_matches;
87-
use oak_package::library::Library;
88-
use oak_package::package::Package;
88+
use oak_library::library::Library;
89+
use oak_library::package::Package;
8990
use oak_package::package_description::Description;
9091
use oak_package::package_namespace::Import;
9192
use oak_package::package_namespace::Namespace;

crates/ark/src/lsp/inputs/source_root.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//
66
//
77

8-
use oak_package::package::Package;
8+
use oak_library::package::Package;
99

1010
/// The root of a source tree.
1111
/// Currently only supports packages, but can be extended to scripts.

crates/ark/src/lsp/main_loop.rs

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use std::sync::RwLock;
1818
use anyhow::anyhow;
1919
use futures::stream::FuturesUnordered;
2020
use futures::StreamExt;
21-
use oak_package::library::Library;
21+
use oak_library::library::Library;
22+
use oak_library::library_definitions::LibraryDefinitions;
23+
use stdext::result::ResultExt;
2224
use tokio::sync::mpsc;
2325
use tokio::sync::mpsc::unbounded_channel as tokio_unbounded_channel;
2426
use tokio::task;
@@ -186,7 +188,7 @@ impl GlobalState {
186188
/// and auxiliary loop.
187189
pub(crate) fn new(
188190
client: Client,
189-
_r_home: PathBuf,
191+
r_home: PathBuf,
190192
console_notification_tx: TokioUnboundedSender<ConsoleNotification>,
191193
) -> Self {
192194
// Transmission channel for the main loop events. Shared with the
@@ -199,30 +201,36 @@ impl GlobalState {
199201
console_notification_tx,
200202
};
201203

202-
let mut state = Self {
203-
world: WorldState::default(),
204-
lsp_state,
205-
client,
206-
events_tx,
207-
events_rx,
208-
};
209-
210204
// FIXME: We shouldn't call R code in the kernel to figure this out
211-
if let Err(err) = crate::r_task(|| -> anyhow::Result<()> {
212-
let paths: Vec<String> = harp::RFunction::new("base", ".libPaths")
205+
let library_paths = crate::r_task(|| -> anyhow::Result<Vec<String>> {
206+
Ok(harp::RFunction::new("base", ".libPaths")
213207
.call()?
214-
.try_into()?;
215-
216-
log::info!("Using library paths: {paths:#?}");
217-
let paths: Vec<PathBuf> = paths.into_iter().map(PathBuf::from).collect();
218-
state.world.library = Library::new(paths);
208+
.try_into()?)
209+
});
219210

220-
Ok(())
221-
}) {
222-
log::error!("Can't evaluate `libPaths()`: {err:?}");
211+
let library_paths = match library_paths {
212+
Ok(library_paths) => library_paths,
213+
Err(err) => {
214+
log::error!("Can't evaluate `libPaths()`: {err:?}");
215+
Vec::new()
216+
},
223217
};
224218

225-
state
219+
let library_paths: Vec<PathBuf> = library_paths.into_iter().map(PathBuf::from).collect();
220+
221+
let library = Library::new(library_paths.clone());
222+
223+
let r = harp::command::r_executable(&r_home);
224+
let library_definitions =
225+
r.and_then(|r| LibraryDefinitions::new(r, library_paths).log_err());
226+
227+
Self {
228+
world: WorldState::new(library, library_definitions),
229+
lsp_state,
230+
client,
231+
events_tx,
232+
events_rx,
233+
}
226234
}
227235

228236
/// Get `Event` transmission channel

0 commit comments

Comments
 (0)