Skip to main content

shuck_server/
lib.rs

1#![warn(missing_docs)]
2#![cfg_attr(not(test), warn(clippy::unwrap_used))]
3
4//! Language Server Protocol support for Shuck.
5//!
6//! The primary entrypoint is [`run`], which starts the server over standard
7//! input and output. A small set of document/session types is also exposed for
8//! integration tests and embedding scenarios that need an in-memory LSP server.
9
10use std::num::NonZeroUsize;
11
12pub use edit::{DocumentKey, PositionEncoding, TextDocument};
13pub use lint::generate_diagnostics;
14use lsp_types::CodeActionKind;
15pub use server::Server;
16pub use session::{Client, ClientOptions, DocumentQuery, DocumentSnapshot, GlobalOptions, Session};
17pub use workspace::{Workspace, Workspaces};
18
19mod analysis;
20mod edit;
21mod editor;
22mod editor_features;
23mod fix;
24mod format;
25#[cfg(feature = "fuzzing")]
26#[doc(hidden)]
27pub mod fuzzing;
28mod lint;
29mod logging;
30mod resolve;
31mod server;
32mod session;
33mod symbols;
34mod workspace;
35
36pub(crate) const SERVER_NAME: &str = "shuck";
37pub(crate) const DIAGNOSTIC_NAME: &str = "shuck";
38
39pub(crate) const SOURCE_FIX_ALL_SHUCK: CodeActionKind = CodeActionKind::new("source.fixAll.shuck");
40
41pub(crate) type Result<T> = anyhow::Result<T>;
42
43pub(crate) fn version() -> &'static str {
44    env!("CARGO_PKG_VERSION")
45}
46
47/// Run the Shuck language server over standard input and output.
48pub fn run() -> Result<()> {
49    let four = NonZeroUsize::try_from(4usize)
50        .map_err(|_| anyhow::anyhow!("failed to create non-zero worker count"))?;
51    let worker_threads = std::thread::available_parallelism()
52        .unwrap_or(four)
53        .min(four);
54
55    let (connection, io_threads) = server::ConnectionInitializer::stdio();
56    let server_result = Server::new(worker_threads, connection)
57        .map_err(|err| err.context("Failed to start server"))?
58        .run();
59
60    let io_result = io_threads.join();
61    match (server_result, io_result) {
62        (Ok(()), Ok(())) => Ok(()),
63        (Err(server), Ok(())) => Err(server),
64        (Ok(()), Err(io)) => Err(anyhow::Error::new(io).context("IO thread error")),
65        (Err(server), Err(io)) => Err(server.context(format!("IO thread error: {io}"))),
66    }
67}
68
69#[doc(hidden)]
70pub fn run_connection(connection: lsp_server::Connection) -> Result<()> {
71    let four = NonZeroUsize::try_from(4usize)
72        .map_err(|_| anyhow::anyhow!("failed to create non-zero worker count"))?;
73    let worker_threads = std::thread::available_parallelism()
74        .unwrap_or(four)
75        .min(four);
76    Server::new(
77        worker_threads,
78        server::ConnectionInitializer::from_connection(connection),
79    )
80    .map_err(|err| err.context("Failed to start server"))?
81    .run()
82}