mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-14 06:15:07 +00:00
weeeee
This commit is contained in:
parent
361d7e2598
commit
00fef522ad
5 changed files with 44 additions and 47 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -518,6 +518,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"tokio",
|
||||
"tower-lsp-server",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ impl LanguageServer for DjangoLanguageServer {
|
|||
language_id,
|
||||
);
|
||||
|
||||
session.open_document(url, document);
|
||||
session.open_document(&url, document);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ use djls_workspace::{
|
|||
db::{Database, SourceFile},
|
||||
paths, Buffers, FileSystem, OsFileSystem, TextDocument, WorkspaceFileSystem,
|
||||
};
|
||||
use salsa::{Setter, StorageHandle};
|
||||
use salsa::StorageHandle;
|
||||
use tower_lsp_server::lsp_types;
|
||||
use url::Url;
|
||||
|
||||
|
@ -286,13 +286,13 @@ impl Session {
|
|||
/// This method coordinates both layers:
|
||||
/// - Layer 1: Stores the document content in buffers
|
||||
/// - Layer 2: Creates the SourceFile in Salsa (if path is resolvable)
|
||||
pub fn open_document(&mut self, url: Url, document: TextDocument) {
|
||||
pub fn open_document(&mut self, url: &Url, document: TextDocument) {
|
||||
tracing::debug!("Opening document: {}", url);
|
||||
|
||||
// Layer 1: Set buffer
|
||||
self.buffers.open(url.clone(), document);
|
||||
|
||||
// Layer 2: Create file and bump revision if it already exists
|
||||
// Layer 2: Create file and touch if it already exists
|
||||
// This is crucial: if the file was already read from disk, we need to
|
||||
// invalidate Salsa's cache so it re-reads through the buffer system
|
||||
if let Some(path) = paths::url_to_path(&url) {
|
||||
|
@ -302,16 +302,8 @@ impl Session {
|
|||
let file = db.get_or_create_file(path.clone());
|
||||
|
||||
if already_exists {
|
||||
// File was already read - bump revision to invalidate cache
|
||||
let current_rev = file.revision(db);
|
||||
let new_rev = current_rev + 1;
|
||||
file.set_revision(db).to(new_rev);
|
||||
tracing::debug!(
|
||||
"Bumped revision for {} on open: {} -> {}",
|
||||
path.display(),
|
||||
current_rev,
|
||||
new_rev
|
||||
);
|
||||
// File was already read - touch to invalidate cache
|
||||
db.touch_file(&path);
|
||||
} else {
|
||||
// New file - starts at revision 0
|
||||
tracing::debug!(
|
||||
|
@ -336,9 +328,9 @@ impl Session {
|
|||
// Layer 1: Update buffer
|
||||
self.buffers.update(url.clone(), document);
|
||||
|
||||
// Layer 2: Bump revision to trigger invalidation
|
||||
// Layer 2: Touch file to trigger invalidation
|
||||
if let Some(path) = paths::url_to_path(url) {
|
||||
self.notify_file_changed(&path);
|
||||
self.with_db_mut(|db| db.touch_file(&path));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,43 +375,15 @@ impl Session {
|
|||
);
|
||||
}
|
||||
|
||||
// Layer 2: Bump revision to trigger re-read from disk
|
||||
// Layer 2: Touch file to trigger re-read from disk
|
||||
// We keep the file alive for potential re-opening
|
||||
if let Some(path) = paths::url_to_path(url) {
|
||||
self.notify_file_changed(&path);
|
||||
self.with_db_mut(|db| db.touch_file(&path));
|
||||
}
|
||||
|
||||
removed
|
||||
}
|
||||
|
||||
/// Internal: Notify that a file's content has changed.
|
||||
///
|
||||
/// This bumps the file's revision number in Salsa, which triggers
|
||||
/// invalidation of any queries that depend on the file's content.
|
||||
fn notify_file_changed(&mut self, path: &Path) {
|
||||
self.with_db_mut(|db| {
|
||||
// Only bump revision if file is already being tracked
|
||||
// We don't create files just for notifications
|
||||
if db.has_file(path) {
|
||||
let file = db.get_or_create_file(path.to_path_buf());
|
||||
let current_rev = file.revision(db);
|
||||
let new_rev = current_rev + 1;
|
||||
file.set_revision(db).to(new_rev);
|
||||
tracing::debug!(
|
||||
"Bumped revision for {}: {} -> {}",
|
||||
path.display(),
|
||||
current_rev,
|
||||
new_rev
|
||||
);
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"File {} not tracked, skipping revision bump",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Safe Query API =====
|
||||
// These methods encapsulate all Salsa interactions, preventing the
|
||||
// "mixed database instance" bug by never exposing SourceFile or Database.
|
||||
|
@ -503,7 +467,7 @@ mod tests {
|
|||
1,
|
||||
LanguageId::Other,
|
||||
);
|
||||
session.open_document(url.clone(), document);
|
||||
session.open_document(&url, document);
|
||||
|
||||
// Try to read content - this might be where it hangs
|
||||
println!("**[test]** try to read content - this might be where it hangs");
|
||||
|
|
|
@ -15,6 +15,7 @@ percent-encoding = { workspace = true }
|
|||
salsa = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tower-lsp-server = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -32,6 +32,7 @@ use std::sync::Arc;
|
|||
use std::sync::Mutex;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use salsa::Setter;
|
||||
|
||||
use crate::{FileKind, FileSystem};
|
||||
|
||||
|
@ -160,6 +161,36 @@ impl Database {
|
|||
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
|
||||
);
|
||||
}
|
||||
|
||||
/// Get a reference to the storage for handle extraction.
|
||||
///
|
||||
/// This is used by `Session` to extract the [`StorageHandle`](salsa::StorageHandle) after mutations.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue