use std::path::Path;
use std::path::PathBuf;
use deno_tower_lsp::lsp_types::ClientCapabilities;
use deno_tower_lsp::lsp_types::Notebook;
use deno_tower_lsp::lsp_types::NotebookCellTextDocumentFilter;
use deno_tower_lsp::lsp_types::NotebookDocumentFilter;
use deno_tower_lsp::lsp_types::NotebookDocumentSyncOptions;
use deno_tower_lsp::lsp_types::NotebookSelector;
use deno_tower_lsp::lsp_types::Registration;
use dprint_core::plugins::FormatRange;
use super::language::get_language_file_name;
pub fn get_notebook_document_sync_options() -> NotebookDocumentSyncOptions {
NotebookDocumentSyncOptions {
notebook_selector: vec![NotebookSelector::ByNotebook {
notebook: file_system_notebook(),
cells: None, }],
save: None,
}
}
pub fn get_notebook_cell_format_registrations(capabilities: &ClientCapabilities) -> Vec<Registration> {
if capabilities.notebook_document.is_none() {
return Vec::new();
}
let Some(text_document) = &capabilities.text_document else {
return Vec::new();
};
let options = serde_json::json!({
"documentSelector": [NotebookCellTextDocumentFilter {
notebook: file_system_notebook(),
language: None,
}],
});
[
("textDocument/formatting", &text_document.formatting),
("textDocument/rangeFormatting", &text_document.range_formatting),
]
.into_iter()
.filter(|(_, capability)| capability.as_ref().and_then(|c| c.dynamic_registration) == Some(true))
.map(|(method, _)| Registration {
id: format!("dprint-notebook-cell-{}", method),
method: method.to_string(),
register_options: Some(options.clone()),
})
.collect()
}
pub fn get_notebook_cell_file_path(notebook_path: &Path, language_id: &str) -> Option<PathBuf> {
Some(notebook_path.parent()?.join(get_language_file_name("code_block", language_id)?))
}
pub fn trim_formatted_cell_text(original_text: &str, mut formatted_text: String, range: &FormatRange) -> String {
formatted_text.truncate(formatted_text.trim_end().len());
if let Some(range) = range
&& range.end < original_text.len()
{
formatted_text.push_str(&original_text[original_text.trim_end().len()..]);
}
formatted_text
}
fn file_system_notebook() -> Notebook {
Notebook::NotebookDocumentFilter(NotebookDocumentFilter::ByScheme {
notebook_type: None,
scheme: "file".to_string(),
pattern: None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_notebook_document_sync_options() {
assert_eq!(
serde_json::to_value(get_notebook_document_sync_options()).unwrap(),
serde_json::json!({ "notebookSelector": [{ "notebook": { "scheme": "file" } }] })
);
}
#[test]
fn test_get_notebook_cell_format_registrations() {
fn get(capabilities: serde_json::Value) -> Vec<String> {
let registrations = get_notebook_cell_format_registrations(&serde_json::from_value(capabilities).unwrap());
for registration in ®istrations {
assert_eq!(
registration.register_options,
Some(serde_json::json!({ "documentSelector": [{ "notebook": { "scheme": "file" } }] }))
);
}
registrations.into_iter().map(|r| r.method).collect()
}
assert_eq!(
get(serde_json::json!({
"notebookDocument": { "synchronization": {} },
"textDocument": {
"formatting": { "dynamicRegistration": true },
"rangeFormatting": { "dynamicRegistration": true },
}
})),
vec!["textDocument/formatting", "textDocument/rangeFormatting"]
);
assert_eq!(
get(serde_json::json!({
"notebookDocument": { "synchronization": {} },
"textDocument": {
"formatting": { "dynamicRegistration": true },
"rangeFormatting": { "dynamicRegistration": false },
}
})),
vec!["textDocument/formatting"]
);
assert_eq!(
get(serde_json::json!({
"textDocument": {
"formatting": { "dynamicRegistration": true },
"rangeFormatting": { "dynamicRegistration": true },
}
})),
Vec::<String>::new()
);
assert_eq!(get(serde_json::json!({})), Vec::<String>::new());
}
#[test]
fn test_get_notebook_cell_file_path() {
fn get(language_id: &str) -> Option<PathBuf> {
get_notebook_cell_file_path(Path::new("/dir/notebook.ipynb"), language_id)
}
assert_eq!(get("python"), Some(PathBuf::from("/dir/code_block.py")));
assert_eq!(get("TypeScript"), Some(PathBuf::from("/dir/code_block.ts")));
assert_eq!(get("markdown"), Some(PathBuf::from("/dir/code_block.md")));
assert_eq!(get("sql"), Some(PathBuf::from("/dir/code_block.sql")));
assert_eq!(get(""), None);
assert_eq!(get("objective-c"), None);
assert_eq!(get("ipynb"), None);
}
#[test]
fn test_trim_formatted_cell_text() {
fn trim(original_text: &str, formatted_text: &str, range: FormatRange) -> String {
trim_formatted_cell_text(original_text, formatted_text.to_string(), &range)
}
assert_eq!(trim("a ", "a\n", None), "a");
assert_eq!(trim("a;b \n", "a;\nb;\n", Some(2..5)), "a;\nb;");
assert_eq!(trim("a;b \n", "a;\nb\n", Some(0..2)), "a;\nb \n");
}
}