use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
use tower_lsp::lsp_types::Url;
#[derive(Debug, Clone)]
pub struct DocumentState {
#[allow(dead_code)]
pub uri: Url,
#[allow(dead_code)]
pub path: PathBuf,
pub version: i32,
pub content: String,
}
impl DocumentState {
pub fn new(uri: Url, content: String, version: i32) -> Self {
let path = uri
.to_file_path()
.unwrap_or_else(|_| PathBuf::from(uri.path()));
Self {
uri,
path,
version,
content,
}
}
}
#[derive(Debug, Default)]
pub struct DocumentManager {
documents: Arc<RwLock<HashMap<Url, DocumentState>>>,
}
impl DocumentManager {
pub fn new() -> Self {
Self {
documents: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn open(&self, uri: Url, content: String, version: i32) {
let state = DocumentState::new(uri.clone(), content, version);
let mut docs = self.documents.write().await;
docs.insert(uri, state);
}
pub async fn change(&self, uri: &Url, content: String, version: i32) {
let mut docs = self.documents.write().await;
if let Some(state) = docs.get_mut(uri) {
state.content = content;
state.version = version;
}
}
pub async fn close(&self, uri: &Url) {
let mut docs = self.documents.write().await;
docs.remove(uri);
}
#[allow(dead_code)]
pub async fn get(&self, uri: &Url) -> Option<DocumentState> {
let docs = self.documents.read().await;
docs.get(uri).cloned()
}
#[allow(dead_code)]
pub async fn get_path(&self, uri: &Url) -> Option<PathBuf> {
let docs = self.documents.read().await;
docs.get(uri).map(|s| s.path.clone())
}
#[allow(dead_code)]
pub async fn all_uris(&self) -> Vec<Url> {
let docs = self.documents.read().await;
docs.keys().cloned().collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_document_lifecycle() {
let manager = DocumentManager::new();
let uri = Url::parse("file:///test/file.py").unwrap();
manager
.open(uri.clone(), "print('hello')".to_string(), 1)
.await;
let state = manager.get(&uri).await;
assert!(state.is_some());
let state = state.unwrap();
assert_eq!(state.version, 1);
assert_eq!(state.content, "print('hello')");
manager.change(&uri, "print('world')".to_string(), 2).await;
let state = manager.get(&uri).await.unwrap();
assert_eq!(state.version, 2);
assert_eq!(state.content, "print('world')");
manager.close(&uri).await;
assert!(manager.get(&uri).await.is_none());
}
}