use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Context;
use qli_core::cache::CacheKey;
use qli_core::AnalysisResult;
use qli_lsp::{AnalysisStore, Pipeline};
use crate::analysis_cache::AnalysisCache;
use crate::{analyze, exit, logging, paths};
const LOG_FILE: &str = "lsp.log";
pub fn run(tcp: Option<u16>, verbose: u8, quiet: bool) -> anyhow::Result<u8> {
if tcp.is_some() {
let path = log_path()?;
logging::init_file(verbose, quiet, &path)
.with_context(|| format!("could not open LSP log file at {}", path.display()))?;
} else {
logging::init(verbose, quiet);
}
paths::ensure_all();
let cache = Arc::new(analyze::build_cache(false));
let store: Arc<dyn AnalysisStore> = Arc::clone(&cache) as _;
let pipeline = Pipeline::new(
analyze::language_registry(),
qli_analyzers::builtin(),
store,
);
match tcp {
Some(port) => qli_lsp::serve_tcp(pipeline, port)
.with_context(|| format!("LSP server failed on 127.0.0.1:{port}"))?,
None => qli_lsp::serve_stdio(pipeline).context("LSP server failed on stdio")?,
}
cache.enforce_size_cap();
Ok(exit::SUCCESS)
}
fn log_path() -> anyhow::Result<PathBuf> {
let dir = paths::state_dir().context("could not resolve XDG state dir for the LSP log")?;
std::fs::create_dir_all(&dir)
.with_context(|| format!("could not create state dir at {}", dir.display()))?;
Ok(dir.join(LOG_FILE))
}
impl AnalysisStore for AnalysisCache {
fn get(&self, key: &CacheKey<'_>) -> Option<AnalysisResult> {
AnalysisCache::get(self, key)
}
fn put(&self, key: &CacheKey<'_>, result: &AnalysisResult) -> std::io::Result<()> {
AnalysisCache::put(self, key, result)
}
}