Skip to content

Commit

Permalink
ls: Support workspace change folder notification
Browse files Browse the repository at this point in the history
This allows to update the list of folders in the workspace
automatically.
  • Loading branch information
artempyanykh committed Aug 22, 2021
1 parent 1c54e58 commit a2560a9
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "zeta-note"
version = "0.1.3"
version = "0.1.4"
authors = ["Artem Pyanykh <artem.pyanykh@gmail.com>"]
edition = "2018"
license-file = "LICENSE"
Expand Down
28 changes: 26 additions & 2 deletions src/lsp/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,48 @@ 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};
use serde_json;

use tracing::debug;

use crate::util::text_matches_query;
use crate::{
diag::{self, DiagCollection, DiagWithLoc},
facts::{NoteFacts, NoteFactsDB, NoteFactsExt},
store::{NoteFile, NoteText, Version},
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
/////////////////////////////////////////
Expand Down
28 changes: 9 additions & 19 deletions src/lsp/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
});
Expand Down Expand Up @@ -188,13 +188,7 @@ pub fn extract_workspace_folders(init_params: &InitializeParams) -> Vec<NoteFold
if let Some(folders) = &init_params.workspace_folders {
folders
.iter()
.map(|f| NoteFolder {
root: f
.uri
.to_file_path()
.expect("Failed to turn URI into a path"),
name: f.name.clone(),
})
.map(NoteFolder::from_workspace_folder)
.collect()
} else {
let root = init_params
Expand All @@ -203,15 +197,8 @@ pub fn extract_workspace_folders(init_params: &InitializeParams) -> Vec<NoteFold
.expect("Expected a `root_uri` parameter")
.to_file_path()
.expect("`root_uri` couldn't be converted to path");
let root_folder = NoteFolder {
root: root.clone(),
name: root
.file_name()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| root.to_string_lossy().to_string()),
};

vec![root_folder]

vec![NoteFolder::from_root_path(&root)]
}
}

Expand Down Expand Up @@ -325,6 +312,9 @@ pub async fn main_loop(connection: Connection, ctx: Ctx) -> Result<()> {
.to_file_path()
.expect("Failed to turn uri into path");
handlers::note_apply_changes(&mut workspace, ctx.client_name, &path, &params);
},
DidChangeWorkspaceFolders => params -> {
handlers::note_change_workspace_folders(&mut workspace, &params.event).await.unwrap();
}
)
}
Expand Down
69 changes: 55 additions & 14 deletions src/store.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;

use glob::Pattern;
use lsp_types::WorkspaceFolder;

use std::{
collections::HashSet,
Expand All @@ -18,29 +19,19 @@ use crate::{
structure::{NoteID, NoteName},
};

#[derive(Default)]
pub struct Workspace {
pub folders: Vec<(NoteFolder, FactsDB, Vec<Pattern>)>,
}

impl Workspace {
pub async fn new(input_folders: &[NoteFolder]) -> Result<Workspace> {
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, &note_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 {
Expand All @@ -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, &note_files, &ignores).await?;
self.folders.push((folder, facts, ignores));
Ok(())
}
}

#[derive(Debug, Clone)]
Expand All @@ -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<Path>,
Expand Down

0 comments on commit a2560a9

Please sign in to comment.