use {
crate::{
TRACER,
Uri,
database::{
DynPartition,
PartitionWriteContextRef,
},
partitions::{
Workspace,
workspace::WorkspaceSortKey,
},
protocol::{
jsonrpc,
lsp::{
DocumentChanges,
NumberOrString,
OneOf,
WorkspaceFolder,
},
macros::lsp_enum,
prelude::*,
},
scheduler::task::TaskContext,
},
serde::{
Deserialize,
Serialize,
},
std::collections::HashMap,
};
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorkspaceEdit {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub changes: Option<HashMap<Uri, Vec<TextEdit>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_changes: Option<DocumentChanges>,
#[serde(skip_serializing_if = "Option::is_none")]
pub change_annotations:
Option<HashMap<ChangeAnnotationIdentifier, ChangeAnnotation>>,
}
impl WorkspaceEdit {
#[must_use]
pub fn new(changes: HashMap<Uri, Vec<TextEdit>>) -> Self {
Self {
changes: Some(changes),
document_changes: None,
..Default::default()
}
}
}
pub trait WorkspaceService<
P: crate::database::storage::Partitions,
T: crate::protocol::lsp::LanguageServer<P>,
>: Send + Sync + 'static
{
fn did_change_configuration(
&self,
params: DidChangeConfigurationParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
let config_json = match serde_json::to_string(¶ms.settings) {
| Ok(json) => json,
| Err(e) => {
return;
},
};
let _ = config_json;
}
}
const DID_CHANGE_CONFIGURATION_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn did_change_workspace_folders(
&self,
params: DidChangeWorkspaceFoldersParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
let source_cache = ctx.source_cache();
let mut cache = source_cache.write();
for folder in params.event.removed {
cache.remove_workspace_folder(&folder.uri);
}
let glob_patterns = ctx.server().source_files_glob();
let mut added_uris = Vec::new();
for folder in params.event.added {
cache.add_workspace_folder(folder.clone());
added_uris.push(folder.uri);
}
drop(cache);
if !added_uris.is_empty() && !glob_patterns.is_empty() {
let task = crate::source::task::SourceCacheIndexTask::create(
ctx.scheduler(),
added_uris,
glob_patterns,
);
ctx.scheduler().queue_task(task);
}
}
}
const DID_CHANGE_WORKSPACE_FOLDERS_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn did_create_files(
&self,
params: CreateFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
otel::span!(
"laburnum.lsp.did_create_files",
"files.count" = params.files.len() as i64
);
let _ = ctx;
let _ = writer;
for file in params.files {
match Uri::parse(&file.uri) {
| Ok(uri) => {},
| Err(e) => {},
}
}
}
}
const DID_CREATE_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn did_rename_files(
&self,
params: RenameFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
otel::span!(
"laburnum.lsp.did_rename_files",
"files.count" = params.files.len() as i64
);
let _ = writer;
let source_cache = ctx.source_cache();
let mut cache = source_cache.write();
for file in params.files {
let old_uri = match Uri::parse(&file.old_uri) {
| Ok(uri) => uri,
| Err(e) => {
continue;
},
};
let new_uri = match Uri::parse(&file.new_uri) {
| Ok(uri) => uri,
| Err(e) => {
continue;
},
};
let new_uri_str = new_uri.to_string();
if let Err(e) = cache.rename_file(&old_uri, new_uri) {
otel::error!(
"file_rename_failed",
format!(
"Failed to rename file from {} to {}: {:?}",
old_uri, new_uri_str, e
)
);
}
}
}
}
const DID_RENAME_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn did_delete_files(
&self,
params: DeleteFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
otel::span!(
"laburnum.lsp.did_delete_files",
"files.count" = params.files.len() as i64
);
let _ = writer;
let source_cache = ctx.source_cache();
let mut cache = source_cache.write();
for file in params.files {
let uri = match Uri::parse(&file.uri) {
| Ok(uri) => uri,
| Err(e) => {
continue;
},
};
if let Err(e) = cache.delete_file(&uri) {
otel::error!(
"file_delete_failed",
format!("Failed to delete file {}: {:?}", uri, e)
);
}
}
}
}
const DID_DELETE_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn did_change_watched_files(
&self,
params: DidChangeWatchedFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = ()> + Send {
async move {
let _ = writer;
let source_cache = ctx.source_cache();
for change in params.changes {
match change.typ {
| FileChangeType::CREATED => {},
| FileChangeType::CHANGED => {},
| FileChangeType::DELETED => {
let mut cache = source_cache.write();
if let Err(e) = cache.delete_file(&change.uri) {}
},
| _ => {},
}
}
}
}
const DID_CHANGE_WATCHED_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
const WORKSPACE_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
}
pub trait WorkspaceHooksService<
P: crate::database::storage::Partitions,
T: crate::protocol::lsp::LanguageServer<P>,
>: Send + Sync + 'static
{
fn will_create_files(
&self,
params: CreateFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = jsonrpc::Result<Option<WorkspaceEdit>>> + Send
{
async move {
otel::span!(
"laburnum.lsp.will_create_files",
"files.count" = params.files.len() as i64
);
let _ = params;
Err(jsonrpc::Error::method_not_found())
}
}
const WILL_CREATE_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn will_rename_files(
&self,
params: RenameFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = jsonrpc::Result<Option<WorkspaceEdit>>> + Send
{
async move {
otel::span!(
"laburnum.lsp.will_rename_files",
"files.count" = params.files.len() as i64
);
let _ = params;
Err(jsonrpc::Error::method_not_found())
}
}
const WILL_RENAME_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
fn will_delete_files(
&self,
params: DeleteFilesParams,
ctx: &mut TaskContext<P, T>,
writer: &mut PartitionWriteContextRef<'_, P>,
) -> impl std::future::Future<Output = jsonrpc::Result<Option<WorkspaceEdit>>> + Send
{
async move {
otel::span!(
"laburnum.lsp.will_delete_files",
"files.count" = params.files.len() as i64
);
let _ = params;
Err(jsonrpc::Error::method_not_found())
}
}
const WILL_DELETE_FILES_LANE: crate::scheduler::lanes::Lane =
crate::scheduler::lanes::DEFAULT_LANE;
}