mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-28 02:39:59 +00:00
## Summary
Closes: astral-sh/ty#88
This PR implements an initial version of a mock language server that can
be used to write e2e tests using the real server running in the
background.
The way it works is that you'd use the `TestServerBuilder` to help
construct the `TestServer` with the setup data. This could be the
workspace folders, populating the file and it's content in the memory
file system, setting the right client capabilities to make the server
respond correctly, etc. This can be expanded as we write more test
cases.
There are still a few things to follow-up on:
- ~In the `Drop` implementation, we should assert that there are no
pending notification, request and responses from the server that the
test code hasn't handled yet~ Implemented in [`afd1f82`
(#19391)](afd1f82bde)
- Reduce the setup boilerplate in any way we can
- Improve the final assertion, currently I'm just snapshotting the final
output
## Test Plan
Written a few test cases.
71 lines
2.1 KiB
Rust
71 lines
2.1 KiB
Rust
use std::{num::NonZeroUsize, sync::Arc};
|
|
|
|
use anyhow::Context;
|
|
use lsp_server::Connection;
|
|
use ruff_db::system::{OsSystem, SystemPathBuf};
|
|
|
|
use crate::server::Server;
|
|
pub use document::{NotebookDocument, PositionEncoding, TextDocument};
|
|
pub(crate) use session::{DocumentQuery, Session};
|
|
|
|
mod document;
|
|
mod logging;
|
|
mod server;
|
|
mod session;
|
|
mod system;
|
|
|
|
#[cfg(test)]
|
|
pub mod test;
|
|
|
|
pub(crate) const SERVER_NAME: &str = "ty";
|
|
pub(crate) const DIAGNOSTIC_NAME: &str = "ty";
|
|
|
|
/// A common result type used in most cases where a
|
|
/// result type is needed.
|
|
pub(crate) type Result<T> = anyhow::Result<T>;
|
|
|
|
pub fn run_server() -> anyhow::Result<()> {
|
|
let four = NonZeroUsize::new(4).unwrap();
|
|
|
|
// by default, we set the number of worker threads to `num_cpus`, with a maximum of 4.
|
|
let worker_threads = std::thread::available_parallelism()
|
|
.unwrap_or(four)
|
|
.min(four);
|
|
|
|
let (connection, io_threads) = Connection::stdio();
|
|
|
|
let cwd = {
|
|
let cwd = std::env::current_dir().context("Failed to get the current working directory")?;
|
|
SystemPathBuf::from_path_buf(cwd).map_err(|path| {
|
|
anyhow::anyhow!(
|
|
"The current working directory `{}` contains non-Unicode characters. \
|
|
ty only supports Unicode paths.",
|
|
path.display()
|
|
)
|
|
})?
|
|
};
|
|
|
|
// This is to complement the `LSPSystem` if the document is not available in the index.
|
|
let fallback_system = Arc::new(OsSystem::new(cwd));
|
|
|
|
let server_result = Server::new(worker_threads, connection, fallback_system, true)
|
|
.context("Failed to start server")?
|
|
.run();
|
|
|
|
let io_result = io_threads.join();
|
|
|
|
let result = match (server_result, io_result) {
|
|
(Ok(()), Ok(())) => Ok(()),
|
|
(Err(server), Err(io)) => Err(server).context(format!("IO thread error: {io}")),
|
|
(Err(server), _) => Err(server),
|
|
(_, Err(io)) => Err(io).context("IO thread error"),
|
|
};
|
|
|
|
if let Err(err) = result.as_ref() {
|
|
tracing::warn!("Server shut down with an error: {err}");
|
|
} else {
|
|
tracing::info!("Server shut down");
|
|
}
|
|
|
|
result
|
|
}
|