mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-10 04:16:30 +00:00
remove left over Database code from workspace crate (#197)
This commit is contained in:
parent
fd0a1c160f
commit
318a395d6f
4 changed files with 47 additions and 165 deletions
|
@ -7,6 +7,8 @@
|
|||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
#[cfg(test)]
|
||||
use std::sync::Mutex;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use djls_templates::db::Db as TemplateDb;
|
||||
|
@ -31,15 +33,49 @@ pub struct DjangoDatabase {
|
|||
files: Arc<DashMap<PathBuf, SourceFile>>,
|
||||
|
||||
storage: salsa::Storage<Self>,
|
||||
|
||||
// The logs are only used for testing and demonstrating reuse:
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
logs: Arc<Mutex<Option<Vec<String>>>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for DjangoDatabase {
|
||||
fn default() -> Self {
|
||||
use djls_workspace::InMemoryFileSystem;
|
||||
|
||||
let logs = <Arc<Mutex<Option<Vec<String>>>>>::default();
|
||||
Self {
|
||||
fs: Arc::new(InMemoryFileSystem::new()),
|
||||
files: Arc::new(DashMap::new()),
|
||||
storage: salsa::Storage::new(Some(Box::new({
|
||||
let logs = logs.clone();
|
||||
move |event| {
|
||||
eprintln!("Event: {event:?}");
|
||||
// Log interesting events, if logging is enabled
|
||||
if let Some(logs) = &mut *logs.lock().unwrap() {
|
||||
// only log interesting events
|
||||
if let salsa::EventKind::WillExecute { .. } = event.kind {
|
||||
logs.push(format!("Event: {event:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}))),
|
||||
logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DjangoDatabase {
|
||||
/// Create a new [`DjangoDatabase`] with the given file system and file map.
|
||||
pub fn new(file_system: Arc<dyn FileSystem>, files: Arc<DashMap<PathBuf, SourceFile>>) -> Self {
|
||||
Self {
|
||||
storage: salsa::Storage::new(None),
|
||||
fs: file_system,
|
||||
files,
|
||||
storage: salsa::Storage::new(None),
|
||||
#[cfg(test)]
|
||||
logs: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,7 @@
|
|||
//! ```
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
#[cfg(test)]
|
||||
use std::sync::Mutex;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use salsa::Setter;
|
||||
|
||||
use crate::FileKind;
|
||||
use crate::FileSystem;
|
||||
|
@ -45,156 +39,6 @@ pub trait Db: salsa::Database {
|
|||
fn read_file_content(&self, path: &Path) -> std::io::Result<String>;
|
||||
}
|
||||
|
||||
/// Temporary concrete database for workspace.
|
||||
///
|
||||
/// This will be moved to the server crate in the refactoring.
|
||||
/// For now, it's kept here to avoid breaking existing code.
|
||||
#[salsa::db]
|
||||
#[derive(Clone)]
|
||||
pub struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
|
||||
/// File system for reading file content (checks buffers first, then disk).
|
||||
fs: Arc<dyn FileSystem>,
|
||||
|
||||
/// Maps paths to [`SourceFile`] entities for O(1) lookup.
|
||||
files: Arc<DashMap<PathBuf, SourceFile>>,
|
||||
|
||||
// The logs are only used for testing and demonstrating reuse:
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
logs: Arc<Mutex<Option<Vec<String>>>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for Database {
|
||||
fn default() -> Self {
|
||||
use crate::fs::InMemoryFileSystem;
|
||||
|
||||
let logs = <Arc<Mutex<Option<Vec<String>>>>>::default();
|
||||
Self {
|
||||
storage: salsa::Storage::new(Some(Box::new({
|
||||
let logs = logs.clone();
|
||||
move |event| {
|
||||
eprintln!("Event: {event:?}");
|
||||
// Log interesting events, if logging is enabled
|
||||
if let Some(logs) = &mut *logs.lock().unwrap() {
|
||||
// only log interesting events
|
||||
if let salsa::EventKind::WillExecute { .. } = event.kind {
|
||||
logs.push(format!("Event: {event:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}))),
|
||||
fs: Arc::new(InMemoryFileSystem::new()),
|
||||
files: Arc::new(DashMap::new()),
|
||||
logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new(file_system: Arc<dyn FileSystem>, files: Arc<DashMap<PathBuf, SourceFile>>) -> Self {
|
||||
Self {
|
||||
storage: salsa::Storage::new(None),
|
||||
fs: file_system,
|
||||
files,
|
||||
#[cfg(test)]
|
||||
logs: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read file content through the file system.
|
||||
pub fn read_file_content(&self, path: &Path) -> std::io::Result<String> {
|
||||
self.fs.read_to_string(path)
|
||||
}
|
||||
|
||||
/// Get an existing [`SourceFile`] for the given path without creating it.
|
||||
///
|
||||
/// Returns `Some(SourceFile)` if the file is already tracked, `None` otherwise.
|
||||
/// This method uses an immutable reference and doesn't modify the database.
|
||||
pub fn get_file(&self, path: &Path) -> Option<SourceFile> {
|
||||
self.files.get(path).map(|file_ref| *file_ref)
|
||||
}
|
||||
|
||||
/// Get or create a [`SourceFile`] for the given path.
|
||||
///
|
||||
/// Files are created with an initial revision of 0 and tracked in the [`Database`]'s
|
||||
/// `DashMap`. The `Arc` ensures cheap cloning while maintaining thread safety.
|
||||
///
|
||||
/// ## Thread Safety
|
||||
///
|
||||
/// This method is inherently thread-safe despite the check-then-create pattern because
|
||||
/// it requires `&mut self`, ensuring exclusive access to the Database. Only one thread
|
||||
/// can call this method at a time due to Rust's ownership rules.
|
||||
pub fn get_or_create_file(&mut self, path: &PathBuf) -> SourceFile {
|
||||
if let Some(file_ref) = self.files.get(path) {
|
||||
// Copy the value (SourceFile is Copy)
|
||||
// The guard drops automatically, no need for explicit drop
|
||||
return *file_ref;
|
||||
}
|
||||
|
||||
// File doesn't exist, so we need to create it
|
||||
let kind = FileKind::from_path(path);
|
||||
let file = SourceFile::new(self, kind, Arc::from(path.to_string_lossy().as_ref()), 0);
|
||||
|
||||
self.files.insert(path.clone(), file);
|
||||
file
|
||||
}
|
||||
|
||||
/// Check if a file is being tracked without creating it.
|
||||
///
|
||||
/// This is primarily used for testing to verify that files have been
|
||||
/// created without affecting the database state.
|
||||
pub fn has_file(&self, path: &Path) -> bool {
|
||||
self.files.contains_key(path)
|
||||
}
|
||||
|
||||
/// Touch a file to mark it as modified, triggering re-evaluation of dependent queries.
|
||||
///
|
||||
/// Similar to Unix `touch`, this updates the file's revision number to signal
|
||||
/// that cached query results depending on this file should be invalidated.
|
||||
///
|
||||
/// This is typically called when:
|
||||
/// - A file is opened in the editor (if it was previously cached from disk)
|
||||
/// - A file's content is modified
|
||||
/// - A file's buffer is closed (reverting to disk content)
|
||||
pub fn touch_file(&mut self, path: &Path) {
|
||||
// Get the file if it exists
|
||||
let Some(file_ref) = self.files.get(path) else {
|
||||
tracing::debug!("File {} not tracked, skipping touch", path.display());
|
||||
return;
|
||||
};
|
||||
let file = *file_ref;
|
||||
drop(file_ref); // Explicitly drop to release the lock
|
||||
|
||||
let current_rev = file.revision(self);
|
||||
let new_rev = current_rev + 1;
|
||||
file.set_revision(self).to(new_rev);
|
||||
|
||||
tracing::debug!(
|
||||
"Touched {}: revision {} -> {}",
|
||||
path.display(),
|
||||
current_rev,
|
||||
new_rev
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.fs.clone()
|
||||
}
|
||||
|
||||
fn read_file_content(&self, path: &Path) -> std::io::Result<String> {
|
||||
self.fs.read_to_string(path)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a single file without storing its content.
|
||||
///
|
||||
/// [`SourceFile`] is a Salsa input entity that tracks a file's path, revision, and
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
//! This module provides the [`FileSystem`] trait that abstracts file I/O operations.
|
||||
//! This allows the LSP to work with both real files and in-memory overlays.
|
||||
|
||||
#[cfg(test)]
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
#[cfg(test)]
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -19,13 +17,12 @@ pub trait FileSystem: Send + Sync {
|
|||
fn exists(&self, path: &Path) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub struct InMemoryFileSystem {
|
||||
files: HashMap<PathBuf, String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl InMemoryFileSystem {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
files: HashMap::new(),
|
||||
|
@ -37,7 +34,12 @@ impl InMemoryFileSystem {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for InMemoryFileSystem {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSystem for InMemoryFileSystem {
|
||||
fn read_to_string(&self, path: &Path) -> io::Result<String> {
|
||||
self.files
|
||||
|
@ -81,7 +83,7 @@ impl FileSystem for OsFileSystem {
|
|||
/// This ensures consistent behavior across all filesystem operations for
|
||||
/// buffered files that may not yet be saved to disk.
|
||||
///
|
||||
/// This type is used by the [`Database`](crate::db::Database) to ensure all file reads go
|
||||
/// This type is used by the database implementations to ensure all file reads go
|
||||
/// through the buffer system first.
|
||||
pub struct WorkspaceFileSystem {
|
||||
/// In-memory buffers that take precedence over disk files
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! # Key Components
|
||||
//!
|
||||
//! - [`Buffers`] - Thread-safe storage for open documents
|
||||
//! - [`Database`] - Salsa database for incremental computation
|
||||
//! - [`Db`] - Database trait for file system access (concrete impl in server crate)
|
||||
//! - [`TextDocument`] - LSP document representation with efficient indexing
|
||||
//! - [`FileSystem`] - Abstraction layer for file operations with overlay support
|
||||
//! - [`paths`] - Consistent URL/path conversion utilities
|
||||
|
@ -24,12 +24,12 @@ mod workspace;
|
|||
use std::path::Path;
|
||||
|
||||
pub use buffers::Buffers;
|
||||
pub use db::Database;
|
||||
pub use db::Db;
|
||||
pub use db::SourceFile;
|
||||
pub use document::TextDocument;
|
||||
pub use encoding::PositionEncoding;
|
||||
pub use fs::FileSystem;
|
||||
pub use fs::InMemoryFileSystem;
|
||||
pub use fs::OsFileSystem;
|
||||
pub use fs::WorkspaceFileSystem;
|
||||
pub use language::LanguageId;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue