mirror of https://github.com/astral-sh/ruff
[red-knot] IDE crate (#17045)
## Summary This PR adds a new but so far empty and unused `red_knot_ide` crate. This new crate's purpose is to implement IDE-specific functionality, such as go to definition, hover, completion, etc., which are used by both the LSP and the playground. The crate itself doesn't depend on `lsptypes`. The idea is that the facade crates (e.g., `red_knot_server`) convert external to internal types. Not only allows this to share the logic between server and playground, it also ensures that the core functionality is easier to test because it can be tested without needing a full LSP. ## Test Plan `cargo build`
This commit is contained in:
parent
a9dbfebc61
commit
b57c62e6b3
|
|
@ -2503,6 +2503,17 @@ dependencies = [
|
||||||
"wild",
|
"wild",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "red_knot_ide"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"red_knot_python_semantic",
|
||||||
|
"red_knot_vendored",
|
||||||
|
"ruff_db",
|
||||||
|
"salsa",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "red_knot_project"
|
name = "red_knot_project"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
@ -2514,6 +2525,7 @@ dependencies = [
|
||||||
"notify",
|
"notify",
|
||||||
"pep440_rs",
|
"pep440_rs",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"red_knot_ide",
|
||||||
"red_knot_python_semantic",
|
"red_knot_python_semantic",
|
||||||
"red_knot_vendored",
|
"red_knot_vendored",
|
||||||
"ruff_cache",
|
"ruff_cache",
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,11 @@ ruff_text_size = { path = "crates/ruff_text_size" }
|
||||||
red_knot_vendored = { path = "crates/red_knot_vendored" }
|
red_knot_vendored = { path = "crates/red_knot_vendored" }
|
||||||
ruff_workspace = { path = "crates/ruff_workspace" }
|
ruff_workspace = { path = "crates/ruff_workspace" }
|
||||||
|
|
||||||
|
red_knot_ide = { path = "crates/red_knot_ide" }
|
||||||
|
red_knot_project = { path = "crates/red_knot_project", default-features = false }
|
||||||
red_knot_python_semantic = { path = "crates/red_knot_python_semantic" }
|
red_knot_python_semantic = { path = "crates/red_knot_python_semantic" }
|
||||||
red_knot_server = { path = "crates/red_knot_server" }
|
red_knot_server = { path = "crates/red_knot_server" }
|
||||||
red_knot_test = { path = "crates/red_knot_test" }
|
red_knot_test = { path = "crates/red_knot_test" }
|
||||||
red_knot_project = { path = "crates/red_knot_project", default-features = false }
|
|
||||||
|
|
||||||
aho-corasick = { version = "1.1.3" }
|
aho-corasick = { version = "1.1.3" }
|
||||||
anstream = { version = "0.6.18" }
|
anstream = { version = "0.6.18" }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
[package]
|
||||||
|
name = "red_knot_ide"
|
||||||
|
version = "0.0.0"
|
||||||
|
publish = false
|
||||||
|
authors = { workspace = true }
|
||||||
|
edition = { workspace = true }
|
||||||
|
rust-version = { workspace = true }
|
||||||
|
homepage = { workspace = true }
|
||||||
|
documentation = { workspace = true }
|
||||||
|
repository = { workspace = true }
|
||||||
|
license = { workspace = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ruff_db = { workspace = true }
|
||||||
|
red_knot_python_semantic = { workspace = true }
|
||||||
|
|
||||||
|
salsa = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
red_knot_vendored = { workspace = true }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
use red_knot_python_semantic::Db as SemanticDb;
|
||||||
|
use ruff_db::{Db as SourceDb, Upcast};
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
pub trait Db: SemanticDb + Upcast<dyn SourceDb> {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::Db;
|
||||||
|
use red_knot_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||||
|
use red_knot_python_semantic::{default_lint_registry, Db as SemanticDb};
|
||||||
|
use ruff_db::files::{File, Files};
|
||||||
|
use ruff_db::system::{DbWithTestSystem, System, TestSystem};
|
||||||
|
use ruff_db::vendored::VendoredFileSystem;
|
||||||
|
use ruff_db::{Db as SourceDb, Upcast};
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct TestDb {
|
||||||
|
storage: salsa::Storage<Self>,
|
||||||
|
files: Files,
|
||||||
|
system: TestSystem,
|
||||||
|
vendored: VendoredFileSystem,
|
||||||
|
events: Arc<std::sync::Mutex<Vec<salsa::Event>>>,
|
||||||
|
rule_selection: Arc<RuleSelection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl TestDb {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
storage: salsa::Storage::default(),
|
||||||
|
system: TestSystem::default(),
|
||||||
|
vendored: red_knot_vendored::file_system().clone(),
|
||||||
|
events: Arc::default(),
|
||||||
|
files: Files::default(),
|
||||||
|
rule_selection: Arc::new(RuleSelection::from_registry(default_lint_registry())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the salsa events.
|
||||||
|
///
|
||||||
|
/// ## Panics
|
||||||
|
/// If there are any pending salsa snapshots.
|
||||||
|
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||||
|
let inner = Arc::get_mut(&mut self.events).expect("no pending salsa snapshots");
|
||||||
|
|
||||||
|
let events = inner.get_mut().unwrap();
|
||||||
|
std::mem::take(&mut *events)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the salsa events.
|
||||||
|
///
|
||||||
|
/// ## Panics
|
||||||
|
/// If there are any pending salsa snapshots.
|
||||||
|
pub(crate) fn clear_salsa_events(&mut self) {
|
||||||
|
self.take_salsa_events();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbWithTestSystem for TestDb {
|
||||||
|
fn test_system(&self) -> &TestSystem {
|
||||||
|
&self.system
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_system_mut(&mut self) -> &mut TestSystem {
|
||||||
|
&mut self.system
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
impl SourceDb for TestDb {
|
||||||
|
fn vendored(&self) -> &VendoredFileSystem {
|
||||||
|
&self.vendored
|
||||||
|
}
|
||||||
|
|
||||||
|
fn system(&self) -> &dyn System {
|
||||||
|
&self.system
|
||||||
|
}
|
||||||
|
|
||||||
|
fn files(&self) -> &Files {
|
||||||
|
&self.files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Upcast<dyn SourceDb> for TestDb {
|
||||||
|
fn upcast(&self) -> &(dyn SourceDb + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn upcast_mut(&mut self) -> &mut (dyn SourceDb + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
impl SemanticDb for TestDb {
|
||||||
|
fn is_file_open(&self, file: File) -> bool {
|
||||||
|
!file.path(self).is_vendored_path()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rule_selection(&self) -> Arc<RuleSelection> {
|
||||||
|
self.rule_selection.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lint_registry(&self) -> &LintRegistry {
|
||||||
|
default_lint_registry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
impl Db for TestDb {}
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
impl salsa::Database for TestDb {
|
||||||
|
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||||
|
let event = event();
|
||||||
|
tracing::trace!("event: {event:?}");
|
||||||
|
let mut events = self.events.lock().unwrap();
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod db;
|
||||||
|
|
||||||
|
pub use db::Db;
|
||||||
|
|
@ -17,6 +17,7 @@ ruff_db = { workspace = true, features = ["cache", "serde"] }
|
||||||
ruff_macros = { workspace = true }
|
ruff_macros = { workspace = true }
|
||||||
ruff_python_ast = { workspace = true, features = ["serde"] }
|
ruff_python_ast = { workspace = true, features = ["serde"] }
|
||||||
ruff_text_size = { workspace = true }
|
ruff_text_size = { workspace = true }
|
||||||
|
red_knot_ide = { workspace = true }
|
||||||
red_knot_python_semantic = { workspace = true, features = ["serde"] }
|
red_knot_python_semantic = { workspace = true, features = ["serde"] }
|
||||||
red_knot_vendored = { workspace = true }
|
red_knot_vendored = { workspace = true }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::DEFAULT_LINT_REGISTRY;
|
use crate::DEFAULT_LINT_REGISTRY;
|
||||||
use crate::{Project, ProjectMetadata};
|
use crate::{Project, ProjectMetadata};
|
||||||
|
use red_knot_ide::Db as IdeDb;
|
||||||
use red_knot_python_semantic::lint::{LintRegistry, RuleSelection};
|
use red_knot_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||||
use red_knot_python_semantic::{Db as SemanticDb, Program};
|
use red_knot_python_semantic::{Db as SemanticDb, Program};
|
||||||
use ruff_db::diagnostic::OldDiagnosticTrait;
|
use ruff_db::diagnostic::OldDiagnosticTrait;
|
||||||
|
|
@ -103,6 +104,19 @@ impl Upcast<dyn SourceDb> for ProjectDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Upcast<dyn IdeDb> for ProjectDatabase {
|
||||||
|
fn upcast(&self) -> &(dyn IdeDb + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upcast_mut(&mut self) -> &mut (dyn IdeDb + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::db]
|
||||||
|
impl IdeDb for ProjectDatabase {}
|
||||||
|
|
||||||
#[salsa::db]
|
#[salsa::db]
|
||||||
impl SemanticDb for ProjectDatabase {
|
impl SemanticDb for ProjectDatabase {
|
||||||
fn is_file_open(&self, file: File) -> bool {
|
fn is_file_open(&self, file: File) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ license = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
red_knot_project = { workspace = true }
|
red_knot_project = { workspace = true }
|
||||||
|
|
||||||
ruff_db = { workspace = true, features = ["os"] }
|
ruff_db = { workspace = true, features = ["os"] }
|
||||||
ruff_notebook = { workspace = true }
|
ruff_notebook = { workspace = true }
|
||||||
ruff_python_ast = { workspace = true }
|
ruff_python_ast = { workspace = true }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue