Skip to content

Commit

Permalink
Add completion database to FeatureRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed May 2, 2019
1 parent f2c2f2a commit 48f56a1
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ lsp-types = "0.56.0"
futures-preview = { version = "0.3.0-alpha.14", features = ["compat"] }
jsonrpc-core = "11.0.0"
jsonrpc-core-client = "11.0.0"
serde = { version = "1.0.90", features = ["derive"] }
serde = { version = "1.0.90", features = ["derive", "rc"] }
serde_json = "1.0.39"
tokio = "0.1"
tokio-stdin-stdout = "0.1"
Expand Down
93 changes: 93 additions & 0 deletions src/completion/latex/data/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::completion::latex::data::types::{LatexComponent, LatexComponentDatabase};
use crate::workspace::{Document, SyntaxTree};
use futures::channel::{mpsc, oneshot};
use futures::compat::*;
use futures::executor::ThreadPool;
use futures::lock::Mutex;
use futures::prelude::*;
use futures::task::*;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::Arc;

enum Message {
Get(oneshot::Sender<Arc<LatexComponentDatabase>>),
Add(LatexComponent),
}

pub struct LatexComponentDatabaseActor {
sender: Mutex<mpsc::Sender<Message>>,
receiver: Mutex<mpsc::Receiver<Message>>,
}

impl LatexComponentDatabaseActor {
pub fn new() -> Self {
let (sender, receiver) = mpsc::channel(0);
LatexComponentDatabaseActor {
sender: Mutex::new(sender),
receiver: Mutex::new(receiver),
}
}

pub async fn spawn(mut pool: ThreadPool, path: PathBuf) -> Arc<Self> {
let actor = Arc::new(Self::new());
let task = |actor: Arc<LatexComponentDatabaseActor>| {
async move {
let mut database = Arc::new(Self::load_database(&path).unwrap_or_default());
let mut receiver = await!(actor.receiver.lock());
while let Some(message) = await!(receiver.next()) {
match message {
Message::Get(sender) => {
let database = Arc::clone(&database);
sender.send(database).unwrap();
}
Message::Add(component) => {
let mut components = Vec::new();
for component in &database.components {
components.push(Arc::clone(&component));
}
components.push(Arc::new(component));
database = Arc::new(LatexComponentDatabase::new(components));
Self::save_database(&path, &database);
}
}
}
}
};
pool.spawn(task(Arc::clone(&actor)))
.expect("Failed to intitialize completion database");
actor
}

fn load_database(path: &Path) -> Option<LatexComponentDatabase> {
let mut file = std::fs::File::open(path).ok()?;
let mut text = String::new();
file.read_to_string(&mut text).ok()?;
serde_json::from_str(&text).ok()
}

fn save_database(path: &Path, database: &LatexComponentDatabase) {
let mut file = std::fs::File::create(path).expect("Failed to create completion database");
let text = serde_json::to_string_pretty(database)
.expect("Failed to serialize completion database");
file.write_all(&mut text.into_bytes())
.expect("Failed to save completion database");
}

pub async fn get(&self) -> Arc<LatexComponentDatabase> {
let (sender, receiver) = oneshot::channel();
let message = Message::Get(sender);
await!(self.send(message));
await!(receiver).unwrap()
}

pub async fn add(&self, component: LatexComponent) {
let message = Message::Add(component);
await!(self.send(message));
}

async fn send(&self, message: Message) {
let mut sender = await!(self.sender.lock());
await!(sender.send(message)).unwrap();
}
}
2 changes: 2 additions & 0 deletions src/completion/latex/data/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod actor;
pub mod types;
65 changes: 65 additions & 0 deletions src/completion/latex/data/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::syntax::latex::analysis::include::LatexIncludeAnalyzer;
use crate::syntax::latex::ast::LatexVisitor;
use crate::workspace::{Document, SyntaxTree};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LatexComponent {
pub files: Vec<String>,
pub references: Vec<String>,
pub commands: Vec<String>,
pub environments: Vec<String>,
}

#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LatexComponentDatabase {
pub components: Vec<Arc<LatexComponent>>,
}

impl LatexComponentDatabase {
pub fn new(components: Vec<Arc<LatexComponent>>) -> Self {
LatexComponentDatabase { components }
}

pub fn related_components(&self, documents: &[&Document]) -> Vec<Arc<LatexComponent>> {
let mut start_components = Vec::new();
for document in documents {
if let SyntaxTree::Latex(tree) = &document.tree {
let mut analyzer = LatexIncludeAnalyzer::new();
analyzer.visit_root(&tree.root);
analyzer
.included_components
.iter()
.flat_map(|file| self.find(&file))
.for_each(|component| start_components.push(component))
}
}

let mut all_components = Vec::new();
for component in start_components {
all_components.push(Arc::clone(&component));
component
.references
.iter()
.flat_map(|file| self.find(&file))
.for_each(|component| all_components.push(component))
}

all_components
.iter()
.unique_by(|component| &component.files)
.map(Arc::clone)
.collect()
}

fn find(&self, name: &String) -> Option<Arc<LatexComponent>> {
self.components
.iter()
.find(|component| component.files.contains(name))
.map(Arc::clone)
}
}
1 change: 1 addition & 0 deletions src/completion/latex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod begin_command;
pub mod color;
pub mod color_model;
mod combinators;
pub mod data;
pub mod kernel_command;
pub mod kernel_environment;
pub mod kernel_primitives;
Expand Down
2 changes: 1 addition & 1 deletion src/completion/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod factory;
mod latex;
pub mod latex;
mod quality;

use crate::completion::latex::begin_command::LatexBeginCommandCompletionProvider;
Expand Down
54 changes: 47 additions & 7 deletions src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ pub struct FeatureRequest<T> {
pub workspace: Arc<Workspace>,
pub document: Arc<Document>,
pub related_documents: Vec<Arc<Document>>,
pub component_database: Arc<LatexComponentDatabase>,
}

impl<T> FeatureRequest<T> {
pub fn new(params: T, workspace: Arc<Workspace>, document: Arc<Document>) -> Self {
pub fn new(
params: T,
workspace: Arc<Workspace>,
document: Arc<Document>,
component_database: Arc<LatexComponentDatabase>,
) -> Self {
let related_documents = workspace.related_documents(&document.uri);
FeatureRequest {
params,
workspace,
document,
related_documents,
component_database,
}
}
}
Expand Down Expand Up @@ -47,6 +54,7 @@ macro_rules! choice_feature {
}};
}

use crate::completion::latex::data::types::LatexComponentDatabase;
#[cfg(test)]
use lsp_types::*;

Expand All @@ -57,6 +65,7 @@ pub struct FeatureTester {
document_id: TextDocumentIdentifier,
position: Position,
new_name: String,
component_database: Arc<LatexComponentDatabase>,
}

#[cfg(test)]
Expand All @@ -69,6 +78,7 @@ impl FeatureTester {
document_id: TextDocumentIdentifier::new(uri),
position: Position::new(line, character),
new_name: new_name.to_owned(),
component_database: Arc::new(LatexComponentDatabase::default()),
}
}
}
Expand All @@ -77,7 +87,12 @@ impl FeatureTester {
impl Into<FeatureRequest<TextDocumentPositionParams>> for FeatureTester {
fn into(self) -> FeatureRequest<TextDocumentPositionParams> {
let params = TextDocumentPositionParams::new(self.document_id, self.position);
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}

Expand All @@ -89,7 +104,12 @@ impl Into<FeatureRequest<CompletionParams>> for FeatureTester {
position: self.position,
context: None,
};
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}

Expand All @@ -99,7 +119,12 @@ impl Into<FeatureRequest<FoldingRangeParams>> for FeatureTester {
let params = FoldingRangeParams {
text_document: self.document_id,
};
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}

Expand All @@ -109,7 +134,12 @@ impl Into<FeatureRequest<DocumentLinkParams>> for FeatureTester {
let params = DocumentLinkParams {
text_document: self.document_id,
};
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}

Expand All @@ -123,7 +153,12 @@ impl Into<FeatureRequest<ReferenceParams>> for FeatureTester {
include_declaration: false,
},
};
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}

Expand All @@ -135,6 +170,11 @@ impl Into<FeatureRequest<RenameParams>> for FeatureTester {
position: self.position,
new_name: self.new_name,
};
FeatureRequest::new(params, self.workspace, self.document)
FeatureRequest::new(
params,
self.workspace,
self.document,
self.component_database,
)
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod server;
mod syntax;
mod workspace;

use crate::completion::latex::data::actor::LatexComponentDatabaseActor;
use crate::server::LatexLspServer;
use crate::workspace::WorkspaceActor;
use clap::*;
Expand Down
8 changes: 7 additions & 1 deletion src/server.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::completion::latex::data::types::LatexComponentDatabase;
use crate::completion::{CompletionProvider, COMPLETION_LIMIT};
use crate::definition::DefinitionProvider;
use crate::feature::FeatureRequest;
Expand Down Expand Up @@ -191,7 +192,12 @@ macro_rules! request {
($server:expr, $params:expr) => {{
let workspace = await!($server.workspace.get());
if let Some(document) = workspace.find(&$params.text_document.uri) {
Ok(FeatureRequest::new($params, workspace, document))
Ok(FeatureRequest::new(
$params,
workspace,
document,
Arc::new(LatexComponentDatabase::default()),
))
} else {
let msg = format!("Unknown document: {}", $params.text_document.uri);
Err(msg)
Expand Down

0 comments on commit 48f56a1

Please sign in to comment.