diff --git a/Cargo.lock b/Cargo.lock index 489e67b..c773b00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1128,7 +1128,7 @@ dependencies = [ [[package]] name = "zeta-note" -version = "0.1.3" +version = "0.1.4" dependencies = [ "anyhow", "atty", diff --git a/Cargo.toml b/Cargo.toml index 34a6a2e..0d9771e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zeta-note" -version = "0.1.3" +version = "0.1.4" authors = ["Artem Pyanykh "] edition = "2018" license-file = "LICENSE" diff --git a/src/lsp/handlers.rs b/src/lsp/handlers.rs index 3a4f234..6c69707 100644 --- a/src/lsp/handlers.rs +++ b/src/lsp/handlers.rs @@ -14,7 +14,7 @@ use lsp_types::{ GotoDefinitionParams, Hover, HoverContents, HoverParams, Location, MarkupContent, Position, PublishDiagnosticsParams, SemanticToken, SemanticTokenType, SemanticTokensLegend, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocumentIdentifier, - TextDocumentItem, Url, + TextDocumentItem, Url, WorkspaceFoldersChangeEvent, }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; @@ -22,7 +22,6 @@ use serde_json; use tracing::debug; -use crate::util::text_matches_query; use crate::{ diag::{self, DiagCollection, DiagWithLoc}, facts::{NoteFacts, NoteFactsDB, NoteFactsExt}, @@ -30,8 +29,33 @@ use crate::{ structure::{Element, ElementWithLoc, NoteName}, }; use crate::{lsp::server::ClientName, store::Workspace}; +use crate::{store::NoteFolder, util::text_matches_query}; use lsp_document::{self, IndexedText, TextAdapter}; +////////////////////////////////////////// +// Workspace +///////////////////////////////////////// + +pub async fn note_change_workspace_folders( + workspace: &mut Workspace, + event: &WorkspaceFoldersChangeEvent, +) -> Result<()> { + for removed in &event.removed { + let path = removed + .uri + .to_file_path() + .expect("Couldn't convert URI to a file path"); + workspace.remove_folder(&path) + } + + for added in &event.added { + let folder = NoteFolder::from_workspace_folder(added); + workspace.add_folder(folder).await?; + } + + Ok(()) +} + ////////////////////////////////////////// // Text Sync ///////////////////////////////////////// diff --git a/src/lsp/server.rs b/src/lsp/server.rs index 630b8a0..a830119 100644 --- a/src/lsp/server.rs +++ b/src/lsp/server.rs @@ -13,8 +13,8 @@ use anyhow::{anyhow, Result}; use lsp_server::{Connection, IoThreads, Message}; use lsp_types::{ notification::{ - DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument, Notification, - PublishDiagnostics, + DidChangeTextDocument, DidChangeWorkspaceFolders, DidCloseTextDocument, + DidOpenTextDocument, Notification, PublishDiagnostics, }, request::{ CodeLensRequest, CodeLensResolve, Completion, DocumentLinkRequest, DocumentSymbolRequest, @@ -139,7 +139,7 @@ fn mk_server_caps(ctx: &Ctx) -> ServerCapabilities { server_capabilities.workspace = Some(WorkspaceServerCapabilities { workspace_folders: Some(WorkspaceFoldersServerCapabilities { supported: Some(true), - change_notifications: None, + change_notifications: Some(OneOf::Left(true)), }), file_operations: None, }); @@ -188,13 +188,7 @@ pub fn extract_workspace_folders(init_params: &InitializeParams) -> Vec Vec Result<()> { .to_file_path() .expect("Failed to turn uri into path"); handlers::note_apply_changes(&mut workspace, ctx.client_name, &path, ¶ms); + }, + DidChangeWorkspaceFolders => params -> { + handlers::note_change_workspace_folders(&mut workspace, ¶ms.event).await.unwrap(); } ) } diff --git a/src/store.rs b/src/store.rs index 2846e17..06d026d 100644 --- a/src/store.rs +++ b/src/store.rs @@ -1,6 +1,7 @@ use anyhow::Result; use glob::Pattern; +use lsp_types::WorkspaceFolder; use std::{ collections::HashSet, @@ -18,29 +19,19 @@ use crate::{ structure::{NoteID, NoteName}, }; +#[derive(Default)] pub struct Workspace { pub folders: Vec<(NoteFolder, FactsDB, Vec)>, } impl Workspace { pub async fn new(input_folders: &[NoteFolder]) -> Result { - let mut output_folders = Vec::with_capacity(input_folders.len()); - + let mut workspace = Workspace::default(); for f in input_folders { - let ignores = store::find_ignores(&f.root).await?; - let note_files = store::find_notes(&f.root, &ignores).await?; - debug!( - "Workspace {}: found {} note files", - f.root.display(), - note_files.len() - ); - let facts = facts::FactsDB::from_files(&f.root, ¬e_files, &ignores).await?; - output_folders.push((f.clone(), facts, ignores)); + workspace.add_folder(f.clone()).await?; } - Ok(Workspace { - folders: output_folders, - }) + Ok(workspace) } pub fn note_count(&self) -> usize { @@ -66,6 +57,34 @@ impl Workspace { .find(|(folder, _, _)| file.starts_with(&folder.root)) .map(|(folder, facts, ignores)| (folder, facts, ignores.as_slice())) } + + pub fn remove_folder(&mut self, path: &Path) { + if let Some((idx, _)) = self + .folders + .iter() + .enumerate() + .find(|(_, (folder, _, _))| folder.root == path) + { + self.folders.remove(idx); + } + } + + pub async fn add_folder(&mut self, folder: NoteFolder) -> Result<()> { + if self.owning_folder(&folder.root).is_some() { + return Ok(()); + } + + let ignores = store::find_ignores(&folder.root).await?; + let note_files = store::find_notes(&folder.root, &ignores).await?; + debug!( + "Workspace {}: found {} note files", + folder.root.display(), + note_files.len() + ); + let facts = facts::FactsDB::from_files(&folder.root, ¬e_files, &ignores).await?; + self.folders.push((folder, facts, ignores)); + Ok(()) + } } #[derive(Debug, Clone)] @@ -74,6 +93,28 @@ pub struct NoteFolder { pub name: String, } +impl NoteFolder { + pub fn from_workspace_folder(workspace_folder: &WorkspaceFolder) -> NoteFolder { + NoteFolder { + root: workspace_folder + .uri + .to_file_path() + .expect("Failed to turn URI into a path"), + name: workspace_folder.name.clone(), + } + } + + pub fn from_root_path(root: &Path) -> NoteFolder { + NoteFolder { + root: root.to_path_buf(), + name: root + .file_name() + .map(|s| s.to_string_lossy().to_string()) + .unwrap_or_else(|| root.to_string_lossy().to_string()), + } + } +} + #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct NoteFile { pub root: Arc,