#![doc = include_str!("../readme.md")]
#![allow(async_fn_in_trait)]
pub mod source;
#[cfg(feature = "chumsky")]
pub use laburnum_syntax_macro::laburnum_syntax;
#[cfg(feature = "test")]
pub use source::TestSourceCacheReader;
pub use source::{
MaterializedSource, Source, SourceCache, SourceKey, SourceStale, SourceView,
Span, SpanCache, SpanCacheCheckpoint, SpanData, SpanResolver,
};
use std::sync::{Arc, atomic::AtomicBool};
pub type Spanned<T> = (T, Span);
pub mod hooks;
#[cfg(feature = "chumsky")]
pub mod chumsky;
pub mod database;
pub use database::{
DynPartition, HasPartition, HasPartitionAt, Partition, PartitionReader,
PartitionStore, PartitionWriteContextRef, PartitionWriter, RecordKey,
RecordRef,
gc::{GarbageCollector, GcPhase, GcPolicy},
hlist::{HCons, HNil, Here, There},
query::{
PartitionQueryBuilder, PartitionWaitingQueryBuilder, QueryClient,
TypedPartitionQueryBuilder, TypedPartitionWaitingQueryBuilder,
},
storage::{
ContentAddressedStorage, Partitions, PartitionsBuilder, RecordStorage,
},
};
mod known_idents;
pub mod record;
pub use record::{LaburnumRecord, LaburnumRecordRef, Record};
pub mod diagnostics;
pub mod partitions;
pub mod prelude;
pub mod progress;
pub mod builtin_watchers {
pub use crate::diagnostics::diagnostic_watcher;
}
pub mod errors;
pub use errors::LaburnumError;
pub mod hash;
pub use hash::{ContentHash, ContentHasher, Ident, IdentHashMap, IdentHashSet};
#[doc(hidden)]
pub use paste;
pub mod fs;
pub mod protocol;
pub mod scheduler;
pub mod server;
pub mod uri;
pub use uri::Uri;
#[cfg(feature = "test")]
pub mod test;
pub mod connect;
pub mod daemon;
pub use protocol::jsonrpc::Message;
otel::tracer!();
pub struct Server {
pub shutdown_flag: Arc<AtomicBool>,
thread_handle: Option<std::thread::JoinHandle<()>>,
}
impl Server {
#[cfg(feature = "test")]
pub fn close_test(self) -> Option<std::thread::JoinHandle<()>> {
self
.shutdown_flag
.store(true, std::sync::atomic::Ordering::SeqCst);
self.thread_handle
}
pub fn close(self) -> std::thread::Result<()> {
otel::span!("laburnum.server.close");
eprintln!("DEBUG: Server::close() - Setting shutdown flag");
self
.shutdown_flag
.store(true, std::sync::atomic::Ordering::SeqCst);
match self.thread_handle {
| Some(h) => {
eprintln!("DEBUG: Server::close() - Waiting for thread to join");
let result = h.join();
eprintln!(
"DEBUG: Server::close() - Thread joined: {:?}",
result.is_ok()
);
result.map(|_| ())
},
| None => {
eprintln!("DEBUG: Server::close() - No thread to join");
Ok(())
},
}
}
}
pub struct Laburnum<
P: database::storage::Partitions,
T: protocol::lsp::LanguageServer<P>,
> {
scheduler: std::sync::Arc<scheduler::Scheduler<P, T>>,
io_threads: Option<connect::ipc::IoThreads>,
}
impl<P: database::storage::Partitions>
Laburnum<P, server::LaburnumLanguageServer>
{
pub fn example() -> LaburnumBuilder<P, server::LaburnumLanguageServer> {
LaburnumBuilder::new(Arc::new(server::LaburnumLanguageServer))
}
}
impl<P: database::storage::Partitions, T: protocol::lsp::LanguageServer<P>>
Laburnum<P, T>
where
T: crate::hooks::LaburnumHooks<P, T>,
{
#[allow(clippy::new_ret_no_self)]
pub fn new(server: T) -> LaburnumBuilder<P, T> {
LaburnumBuilder::new(Arc::new(server))
}
pub fn run(mut self) -> Server {
let shutdown_flag = self.scheduler.shutdown_flag.clone();
let thread_handle = otel::span!("laburnum.run", in |cx|{
std::thread::spawn(move || {
let _guard = cx.attach();
self.run_blocking()
})
});
Server {
shutdown_flag,
thread_handle: Some(thread_handle),
}
}
pub fn run_blocking(&mut self) {
self.scheduler.run();
}
pub fn shutdown(self) -> std::io::Result<()> {
if let Some(io_threads) = self.io_threads {
io_threads.join()?;
}
Ok(())
}
}
pub struct LaburnumBuilder<
P: database::storage::Partitions,
T: protocol::lsp::LanguageServer<P>,
> {
server: Arc<T>,
filesystems: Vec<crate::fs::FS>,
scheduler_config: scheduler::SchedulerConfiguration,
_phantom: std::marker::PhantomData<P>,
}
impl<P: database::storage::Partitions, T: protocol::lsp::LanguageServer<P>>
LaburnumBuilder<P, T>
{
pub fn new(server: Arc<T>) -> Self {
Self {
server,
filesystems: Vec::new(),
scheduler_config: scheduler::SchedulerConfiguration::default(),
_phantom: std::marker::PhantomData,
}
}
pub fn filesystem(mut self, fs: crate::fs::FS) -> Self {
self.filesystems.push(fs);
self
}
pub fn scheduler_config(
mut self,
config: scheduler::SchedulerConfiguration,
) -> Self {
self.scheduler_config = config;
self
}
pub fn build_stdio(self) -> std::io::Result<Laburnum<P, T>> {
let (connection, io_threads) = connect::ipc::Connection::stdio()?;
let filesystems =
std::sync::Arc::new(parking_lot::RwLock::new(self.filesystems));
let source_cache =
std::sync::Arc::new(parking_lot::RwLock::new(SourceCache::new()));
let worker_count = num_cpus::get().saturating_sub(1).max(1);
Ok(Laburnum {
scheduler: scheduler::Scheduler::new_with_config(
connection,
self.server,
filesystems,
source_cache,
worker_count,
self.scheduler_config,
),
io_threads: Some(io_threads),
})
}
pub fn build_test(self) -> (Server, connect::lsp::LspClient) {
let (server_conn, client_conn) = connect::ipc::Connection::memory();
let client = connect::lsp::LspClient::new_test(client_conn);
let filesystems =
std::sync::Arc::new(parking_lot::RwLock::new(self.filesystems));
let source_cache =
std::sync::Arc::new(parking_lot::RwLock::new(SourceCache::new()));
let server = Laburnum {
scheduler: scheduler::Scheduler::new_with_config(
server_conn,
self.server,
filesystems,
source_cache,
1,
self.scheduler_config,
),
io_threads: None,
}
.run();
(server, client)
}
pub fn build_server(self, server_conn: connect::ipc::Connection) -> Server {
otel::span!("laburnum.build_server");
let source_cache =
std::sync::Arc::new(parking_lot::RwLock::new(SourceCache::new()));
Laburnum {
scheduler: scheduler::Scheduler::new_with_config(
server_conn,
self.server,
std::sync::Arc::new(parking_lot::RwLock::new(self.filesystems)),
source_cache,
1,
self.scheduler_config,
),
io_threads: None,
}
.run()
}
pub fn build_daemon(
self,
config: daemon::DaemonConfig,
) -> daemon::DaemonServer<P, T>
where
T: hooks::LaburnumHooks<P, T>,
{
otel::span!("laburnum.build_daemon");
let filesystems =
std::sync::Arc::new(parking_lot::RwLock::new(self.filesystems));
let source_cache =
std::sync::Arc::new(parking_lot::RwLock::new(SourceCache::new()));
let worker_count = num_cpus::get().saturating_sub(1).max(1);
daemon::DaemonServer::new(
self.server.clone(),
config,
filesystems,
source_cache,
worker_count,
self.scheduler_config,
)
}
}
pub struct TestHarness {
pub server: Server,
}