use log::error;
use std::{borrow::Cow, io, path::PathBuf};
use thiserror::Error;
use tower_lsp::lsp_types::Url;
use crate::pos::Position;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error("The provided document can not be found {0}")]
DocumentNotFound(Url),
#[error("The provided internal document can not be found {0}")]
InternalDocumentNotFound(PathBuf),
#[error("The provided document was not loaded but requested {0}")]
DocumentNotLoaded(Url),
#[error("The provided document type is not supported extention: {0}")]
DocumentNotSupported(String),
#[error("The provided document was empty: {0}")]
DocumentEmpty(Url),
#[error("The provided file path is not a URL {0}")]
InvalidFilePath(PathBuf),
#[error("The workspace of the document was not found {0}")]
WorkspaceNotFound(Url),
#[error("The lock could not be aquired for {0} sec")]
LockTimeout(u64),
#[error("The provided URL is not valid for this LSP {0}")]
InvalidUrl(Url),
#[error("The position is not inside the bounds {0}")]
PositionOutOfBounds(Position),
#[error("The tower lsp position is not inside the bounds {0:?}")]
PositionOutOfBoundsTowerLsp(tower_lsp::lsp_types::Position),
#[error("The LSP Feature is not supported at the moment: {0}")]
LspFeatureNotSupported(&'static str),
#[error("Frame Info for IRI not found {0}")]
FrameInfoNotFound(String),
#[error("Horned Owl Error: {0}")]
HornedOwl(#[from] horned_owl::error::HornedError),
#[error("IO Error: {0}")]
Io(#[from] io::Error),
#[error("Tokio Join Error: {0}")]
TokioJoin(#[from] tokio::task::JoinError),
#[error("Rope Error: {0}")]
Rope(#[from] ropey::Error),
#[error("Sophia Error: {0}")]
Sophia(String), #[error("Web Error: {0}")]
Web(#[from] crate::web::Error),
}
impl From<Error> for tower_lsp::jsonrpc::Error {
fn from(value: Error) -> Self {
match value {
Error::DocumentNotFound(url) => {
Self::invalid_params(format!("The provided document can not be found {url}"))
}
_ => Self {
code: 0.into(),
message: Cow::from(format!("{value}")),
data: None,
},
}
}
}
pub trait ResultExt<T> {
fn log_if_error(self);
fn inspect_log(self) -> Self;
}
impl<T> ResultExt<T> for Result<T> {
fn log_if_error(self) {
let _ = self.inspect_log();
}
fn inspect_log(self) -> Self {
self.inspect_err(|e| error!("{e}"))
}
}
pub trait ResultIterator<T> {
fn filter_and_log(self) -> impl Iterator<Item = T>;
}
impl<T, I: Iterator<Item = Result<T>>> ResultIterator<T> for I {
fn filter_and_log(self) -> impl Iterator<Item = T> {
self.filter_map(|r| r.inspect_log().ok())
}
}