mirror of
https://github.com/latex-lsp/texlab.git
synced 2025-12-23 09:19:21 +00:00
Add basic salsa DB
This commit is contained in:
parent
cfeead5c24
commit
2f64ce6bbc
11 changed files with 666 additions and 2 deletions
110
Cargo.lock
generated
110
Cargo.lock
generated
|
|
@ -8,6 +8,17 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.19"
|
||||
|
|
@ -38,6 +49,12 @@ version = "1.0.65"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164"
|
||||
|
||||
[[package]]
|
||||
name = "assert_unordered"
|
||||
version = "0.3.5"
|
||||
|
|
@ -286,6 +303,20 @@ dependencies = [
|
|||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.6"
|
||||
|
|
@ -320,6 +351,16 @@ dependencies = [
|
|||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.12"
|
||||
|
|
@ -416,6 +457,16 @@ dependencies = [
|
|||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
|
|
@ -534,6 +585,18 @@ name = "hashbrown"
|
|||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
|
@ -586,6 +649,12 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
|
|
@ -895,6 +964,16 @@ version = "6.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.3"
|
||||
|
|
@ -1171,6 +1250,36 @@ version = "1.0.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "salsa-2022"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa?branch=master#30b5e9760aadc3570dc2ba176f4d74448c4152ed"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"crossbeam",
|
||||
"crossbeam-utils",
|
||||
"dashmap",
|
||||
"hashlink",
|
||||
"indexmap",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"rustc-hash",
|
||||
"salsa-2022-macros",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "salsa-2022-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa?branch=master#30b5e9760aadc3570dc2ba176f4d74448c4152ed"
|
||||
dependencies = [
|
||||
"eyre",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
|
@ -1399,6 +1508,7 @@ dependencies = [
|
|||
"regex",
|
||||
"rowan",
|
||||
"rustc-hash",
|
||||
"salsa-2022",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_millis",
|
||||
|
|
|
|||
|
|
@ -76,6 +76,11 @@ version = "0.99.17"
|
|||
default-features = false
|
||||
features = ["from", "display"]
|
||||
|
||||
[dependencies.salsa]
|
||||
git = "https://github.com/salsa-rs/salsa"
|
||||
branch = "master"
|
||||
package = "salsa-2022"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_unordered = "0.3.5"
|
||||
criterion = { version = "0.4.0" }
|
||||
|
|
|
|||
7
src/db.rs
Normal file
7
src/db.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
mod context;
|
||||
mod document;
|
||||
mod file;
|
||||
mod project;
|
||||
mod workspace;
|
||||
|
||||
pub use self::{context::*, document::*, file::*, project::*, workspace::*};
|
||||
10
src/db/context.rs
Normal file
10
src/db/context.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use crate::distro::Resolver;
|
||||
|
||||
#[salsa::input(singleton)]
|
||||
pub struct ServerContext {
|
||||
#[return_ref]
|
||||
pub file_name_db: Resolver,
|
||||
|
||||
#[return_ref]
|
||||
pub artifact_dir: String,
|
||||
}
|
||||
92
src/db/document.rs
Normal file
92
src/db/document.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
use rowan::GreenNode;
|
||||
|
||||
use crate::{
|
||||
parser::{parse_bibtex, parse_build_log, parse_latex},
|
||||
syntax::{latex, BuildError, BuildLog},
|
||||
Db, LineIndex,
|
||||
};
|
||||
|
||||
use super::{FileId, Language};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||
pub enum OpenedBy {
|
||||
Client,
|
||||
Server,
|
||||
}
|
||||
|
||||
#[salsa::input]
|
||||
pub struct Document {
|
||||
pub file: FileId,
|
||||
#[return_ref]
|
||||
pub text: String,
|
||||
pub language: Language,
|
||||
pub opened_by: OpenedBy,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl Document {
|
||||
#[salsa::tracked]
|
||||
pub fn parse(self, db: &dyn Db) -> DocumentData {
|
||||
let text = self.text(db);
|
||||
match self.language(db) {
|
||||
Language::Tex => {
|
||||
let green = parse_latex(text);
|
||||
DocumentData::Tex(TexDocumentData::new(db, green))
|
||||
}
|
||||
Language::Bib => {
|
||||
let green = parse_bibtex(text);
|
||||
DocumentData::Bib(BibDocumentData::new(db, green))
|
||||
}
|
||||
Language::Log => {
|
||||
let BuildLog { errors } = parse_build_log(text);
|
||||
DocumentData::Log(LogDocumentData::new(db, errors))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn line_index(self, db: &dyn Db) -> LineIndex {
|
||||
LineIndex::new(self.text(db))
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub fn can_be_root(self, db: &dyn Db) -> bool {
|
||||
match self.parse(db) {
|
||||
DocumentData::Tex(data) => data.extras(db).can_be_root,
|
||||
DocumentData::Bib(_) | DocumentData::Log(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||
pub enum DocumentData {
|
||||
Tex(TexDocumentData),
|
||||
Bib(BibDocumentData),
|
||||
Log(LogDocumentData),
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub struct TexDocumentData {
|
||||
pub green: GreenNode,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl TexDocumentData {
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn extras(self, db: &dyn Db) -> latex::Extras {
|
||||
let extras = latex::Extras::default();
|
||||
latex::SyntaxNode::new_root(self.green(db));
|
||||
extras
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub struct BibDocumentData {
|
||||
pub green: GreenNode,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub struct LogDocumentData {
|
||||
#[return_ref]
|
||||
pub errors: Vec<BuildError>,
|
||||
}
|
||||
59
src/db/file.rs
Normal file
59
src/db/file.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use lsp_types::Url;
|
||||
|
||||
use crate::Db;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||
pub enum Language {
|
||||
Tex,
|
||||
Bib,
|
||||
Log,
|
||||
}
|
||||
|
||||
#[salsa::input]
|
||||
pub struct FileId {
|
||||
#[return_ref]
|
||||
pub uri: Url,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl FileId {
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn path(self, db: &dyn Db) -> Option<PathBuf> {
|
||||
let uri = self.uri(db);
|
||||
if uri.scheme() == "file" {
|
||||
uri.to_file_path().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn stem(self, db: &dyn Db) -> Option<String> {
|
||||
let file_name = self.uri(db).path_segments()?.last()?;
|
||||
let file_stem = file_name
|
||||
.rfind('.')
|
||||
.map(|i| &file_name[..i])
|
||||
.unwrap_or(file_name);
|
||||
|
||||
Some(file_stem.to_string())
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub fn language(self, db: &dyn Db) -> Option<Language> {
|
||||
let uri = self.uri(db);
|
||||
let (_, ext) = uri.path_segments()?.last()?.rsplit_once(".")?;
|
||||
match ext.to_lowercase().as_str() {
|
||||
"tex" | "sty" | "cls" | "def" | "lco" | "aux" | "rnw" => Some(Language::Tex),
|
||||
"bib" | "bibtex" => Some(Language::Bib),
|
||||
"log" => Some(Language::Log),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self, db: &dyn Db, path: &str) -> Result<FileId, url::ParseError> {
|
||||
let uri = self.uri(db);
|
||||
Ok(FileId::new(db, uri.join(path)?))
|
||||
}
|
||||
}
|
||||
185
src/db/project.rs
Normal file
185
src/db/project.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
use itertools::Itertools;
|
||||
use lsp_types::Url;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::{
|
||||
component_db::COMPONENT_DATABASE,
|
||||
db::{DocumentData, FileId, Language, ServerContext},
|
||||
distro::Resolver,
|
||||
Db,
|
||||
};
|
||||
|
||||
use super::Document;
|
||||
|
||||
#[salsa::interned]
|
||||
pub struct Dependency {
|
||||
pub document: Document,
|
||||
pub base_dir: FileId,
|
||||
}
|
||||
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn implicit_dependencies_of(db: &dyn Db, parent: Dependency) -> Vec<Dependency> {
|
||||
let context = ServerContext::get(db);
|
||||
|
||||
let mut results = Vec::new();
|
||||
for extension in &["aux", "log"] {
|
||||
let file_name = parent
|
||||
.document(db)
|
||||
.file(db)
|
||||
.stem(db)
|
||||
.as_deref()
|
||||
.map(|stem| format!("{}.{}", stem, extension));
|
||||
|
||||
let child = file_name
|
||||
.and_then(|name| {
|
||||
parent
|
||||
.base_dir(db)
|
||||
.join(db, context.artifact_dir(db))
|
||||
.and_then(|file| file.join(db, &name))
|
||||
.ok()
|
||||
})
|
||||
.and_then(|file| db.workspace().load(db, file));
|
||||
|
||||
if let Some(child) = child {
|
||||
let artifact = Dependency::new(db, child, parent.base_dir(db));
|
||||
results.push(artifact);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn explicit_dependencies_of(db: &dyn Db, parent: Dependency) -> Vec<Dependency> {
|
||||
let resolver = Resolver::default();
|
||||
let mut results = Vec::new();
|
||||
let data = match parent.document(db).parse(db) {
|
||||
DocumentData::Tex(data) => data,
|
||||
_ => return results,
|
||||
};
|
||||
|
||||
let extras = data.extras(db);
|
||||
for link in &extras.explicit_links {
|
||||
if link
|
||||
.as_component_name()
|
||||
.and_then(|name| COMPONENT_DATABASE.find(&name))
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut targets = link
|
||||
.targets(parent.base_dir(db).uri(db), &resolver)
|
||||
.map(|uri| FileId::new(db, uri));
|
||||
|
||||
if let Some(child) = targets.find_map(|file| db.workspace().load(db, file)) {
|
||||
let base_dir = link
|
||||
.working_dir
|
||||
.as_ref()
|
||||
.and_then(|path| parent.base_dir(db).join(db, path).ok())
|
||||
.unwrap_or_else(|| parent.base_dir(db));
|
||||
|
||||
results.push(Dependency::new(db, child, base_dir));
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[salsa::interned]
|
||||
pub struct Project {
|
||||
pub root: Document,
|
||||
|
||||
#[return_ref]
|
||||
pub dependencies: Vec<Dependency>,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
pub fn documents<'db>(self, db: &'db dyn Db) -> impl Iterator<Item = Document> + 'db {
|
||||
self.dependencies(db)
|
||||
.iter()
|
||||
.map(|dependency| dependency.document(db))
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub fn project_of(db: &dyn Db, root: Document) -> Project {
|
||||
let mut results = Vec::new();
|
||||
let mut visited = FxHashSet::default();
|
||||
let mut stack = vec![Dependency::new(db, root, root.file(db))];
|
||||
while let Some(dependency) = stack.pop() {
|
||||
if !visited.insert(dependency.document(db)) {
|
||||
break;
|
||||
}
|
||||
|
||||
results.push(dependency);
|
||||
stack.extend(explicit_dependencies_of(db, dependency));
|
||||
stack.extend(implicit_dependencies_of(db, dependency));
|
||||
}
|
||||
|
||||
Project::new(db, root, results)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub struct ProjectGroup {
|
||||
#[return_ref]
|
||||
pub projects: Vec<Project>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl ProjectGroup {
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn union(self, db: &dyn Db) -> Vec<Document> {
|
||||
self.projects(db)
|
||||
.iter()
|
||||
.flat_map(|project| project.documents(db))
|
||||
.unique()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub fn project_group_of(db: &dyn Db, child: Document) -> ProjectGroup {
|
||||
let ancestors = child
|
||||
.file(db)
|
||||
.path(db)
|
||||
.into_iter()
|
||||
.flat_map(|path| path.ancestors());
|
||||
|
||||
fn find(db: &dyn Db, child: Document) -> Vec<Project> {
|
||||
db.workspace()
|
||||
.iter()
|
||||
.filter(|doc| doc.can_be_root(db))
|
||||
.map(|root| project_of(db, root))
|
||||
.filter(|project| project.documents(db).contains(&child))
|
||||
.collect()
|
||||
}
|
||||
|
||||
for path in ancestors {
|
||||
let projects = find(db, child);
|
||||
|
||||
if !projects.is_empty() {
|
||||
return ProjectGroup::new(db, projects);
|
||||
}
|
||||
|
||||
let files = std::fs::read_dir(path)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|entry| entry.file_type().map_or(false, |ty| ty.is_file()))
|
||||
.filter_map(|entry| Url::from_file_path(entry.path()).ok())
|
||||
.map(|uri| FileId::new(db, uri))
|
||||
.filter(|file| file.language(db) == Some(Language::Tex));
|
||||
|
||||
for file in files {
|
||||
db.workspace().load(db, file);
|
||||
}
|
||||
}
|
||||
|
||||
let mut projects = find(db, child);
|
||||
if projects.is_empty() {
|
||||
projects = vec![project_of(db, child)];
|
||||
}
|
||||
|
||||
ProjectGroup::new(db, projects)
|
||||
}
|
||||
90
src/db/workspace.rs
Normal file
90
src/db/workspace.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use dashmap::DashMap;
|
||||
|
||||
use crate::{db::Document, Db};
|
||||
|
||||
use super::{FileId, Language, OpenedBy};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Workspace {
|
||||
documents: DashMap<FileId, Option<Document>>,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
pub fn open(
|
||||
&self,
|
||||
db: &mut dyn Db,
|
||||
file: FileId,
|
||||
text: String,
|
||||
language: Language,
|
||||
) -> Document {
|
||||
match self.get(file) {
|
||||
Some(document) => {
|
||||
document
|
||||
.set_text(db)
|
||||
.with_durability(salsa::Durability::LOW)
|
||||
.to(text);
|
||||
|
||||
document
|
||||
.set_language(db)
|
||||
.with_durability(salsa::Durability::HIGH)
|
||||
.to(language);
|
||||
|
||||
document
|
||||
.set_opened_by(db)
|
||||
.with_durability(salsa::Durability::LOW)
|
||||
.to(OpenedBy::Client);
|
||||
|
||||
document
|
||||
}
|
||||
None => {
|
||||
let document = Document::new(db, file, text, language, OpenedBy::Client);
|
||||
self.documents.insert(file, Some(document));
|
||||
document
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&self, db: &dyn Db, file: FileId) -> Option<Document> {
|
||||
*self.documents.entry(file).or_insert_with(|| {
|
||||
let path = file.path(db).as_deref()?;
|
||||
let data = std::fs::read(path).ok()?;
|
||||
let text = match String::from_utf8_lossy(&data) {
|
||||
Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(data) },
|
||||
Cow::Owned(text) => text,
|
||||
};
|
||||
|
||||
let language = file.language(db)?;
|
||||
Some(Document::new(db, file, text, language, OpenedBy::Server))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn close(&self, db: &mut dyn Db, file: FileId) {
|
||||
self.documents.alter(&file, |_, document| {
|
||||
if let Some(doc) = document {
|
||||
doc.set_opened_by(db)
|
||||
.with_durability(salsa::Durability::LOW)
|
||||
.to(OpenedBy::Server);
|
||||
}
|
||||
|
||||
document
|
||||
});
|
||||
}
|
||||
|
||||
pub fn remove_if<F>(&self, file: FileId, predicate: F)
|
||||
where
|
||||
F: FnOnce(Document) -> bool,
|
||||
{
|
||||
self.documents
|
||||
.remove_if(&file, |_, doc| doc.map_or(false, predicate));
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = Document> + 'a {
|
||||
self.documents.iter().filter_map(|entry| *entry)
|
||||
}
|
||||
|
||||
fn get(&self, file: FileId) -> Option<Document> {
|
||||
*self.documents.get(&file)?
|
||||
}
|
||||
}
|
||||
65
src/lib.rs
65
src/lib.rs
|
|
@ -2,6 +2,7 @@ mod capabilities;
|
|||
pub mod citation;
|
||||
mod client;
|
||||
pub mod component_db;
|
||||
pub mod db;
|
||||
mod debouncer;
|
||||
mod diagnostics;
|
||||
mod dispatch;
|
||||
|
|
@ -21,6 +22,8 @@ mod server;
|
|||
pub mod syntax;
|
||||
mod workspace;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use self::{
|
||||
capabilities::ClientCapabilitiesExt,
|
||||
document::*,
|
||||
|
|
@ -54,3 +57,65 @@ pub(crate) fn normalize_uri(uri: &mut lsp_types::Url) {
|
|||
|
||||
uri.set_fragment(None);
|
||||
}
|
||||
|
||||
#[salsa::jar(db = Db)]
|
||||
pub struct Jar(
|
||||
db::ServerContext,
|
||||
db::FileId,
|
||||
db::FileId_path,
|
||||
db::FileId_stem,
|
||||
db::FileId_language,
|
||||
db::Document,
|
||||
db::Document_parse,
|
||||
db::Document_line_index,
|
||||
db::Document_can_be_root,
|
||||
db::TexDocumentData,
|
||||
db::TexDocumentData_extras,
|
||||
db::BibDocumentData,
|
||||
db::LogDocumentData,
|
||||
db::Dependency,
|
||||
db::implicit_dependencies_of,
|
||||
db::explicit_dependencies_of,
|
||||
db::Project,
|
||||
db::project_of,
|
||||
db::ProjectGroup,
|
||||
db::ProjectGroup_union,
|
||||
db::project_group_of,
|
||||
);
|
||||
|
||||
pub trait Db: salsa::DbWithJar<Jar> {
|
||||
fn workspace(&self) -> Arc<db::Workspace>;
|
||||
}
|
||||
|
||||
#[salsa::db(crate::Jar)]
|
||||
pub(crate) struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
workspace: Arc<db::Workspace>,
|
||||
}
|
||||
|
||||
impl Default for Database {
|
||||
fn default() -> Self {
|
||||
let storage = salsa::Storage::default();
|
||||
let workspace = Arc::default();
|
||||
let db = Self { storage, workspace };
|
||||
db::ServerContext::new(&db, distro::Resolver::default(), ".".to_string());
|
||||
db
|
||||
}
|
||||
}
|
||||
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl salsa::ParallelDatabase for Database {
|
||||
fn snapshot(&self) -> salsa::Snapshot<Self> {
|
||||
salsa::Snapshot::new(Self {
|
||||
storage: self.storage.snapshot(),
|
||||
workspace: self.workspace(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Db for Database {
|
||||
fn workspace(&self) -> Arc<db::Workspace> {
|
||||
Arc::clone(&self.workspace)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub struct LatexAnalyzerContext<'a> {
|
|||
pub extras: Extras,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||
pub struct Extras {
|
||||
pub implicit_links: ImplicitLinks,
|
||||
pub explicit_links: Vec<ExplicitLink>,
|
||||
|
|
@ -45,7 +45,7 @@ pub enum ExplicitLinkKind {
|
|||
Bibtex,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct ExplicitLink {
|
||||
pub stem: SmolStr,
|
||||
pub stem_range: TextRange,
|
||||
|
|
|
|||
|
|
@ -298,3 +298,44 @@ fn change_extension(uri: &Url, extension: &str) -> Option<String> {
|
|||
|
||||
Some(format!("{}.{}", file_stem, extension))
|
||||
}
|
||||
|
||||
// fn explore_project(
|
||||
// root: &Document,
|
||||
// working_dir: &Url,
|
||||
// resolver: &Resolver,
|
||||
// visited: &mut FxHashSet<Arc<Url>>,
|
||||
// results: &mut Vec<Document>,
|
||||
// ) {
|
||||
// if !visited.insert(Arc::clone(root.uri())) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// results.push(root.clone());
|
||||
// if let Some(data) = root.data().as_latex() {
|
||||
// for link in &data.extras.explicit_links {
|
||||
// if link
|
||||
// .as_component_name()
|
||||
// .and_then(|name| COMPONENT_DATABASE.find(&name))
|
||||
// .is_some()
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if let Some(child) = link
|
||||
// .targets(&working_dir, resolver)
|
||||
// .find_map(|uri| self.get(&uri))
|
||||
// {
|
||||
// explore_project(&child, &working_dir, visited, results);
|
||||
// }
|
||||
// }
|
||||
|
||||
// for extension in &["aux", "log"] {
|
||||
// if let Some(child) = change_extension(root.uri(), extension)
|
||||
// .and_then(|file_name| working_dir.join(&file_name).ok())
|
||||
// .and_then(|uri| self.get(&uri))
|
||||
// {
|
||||
// explore_project(&child, &working_dir, visited, results);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue