use anyhow::{anyhow, Result};
use colored::Colorize;
use pulldown_cmark::{html, Options, Parser};
use std::{
fs,
path::{Path, PathBuf},
};
pub trait Read: Sized {
fn file_name(&self) -> Result<String>;
fn read(&self) -> Result<String>;
}
impl<P> Read for P
where
P: AsRef<Path>,
{
fn file_name(&self) -> Result<String> {
self.as_ref()
.file_name()
.ok_or_else(|| anyhow::anyhow!("Failed to get file name: {}", self.as_ref().display()))
.map(|s| s.to_string_lossy().to_string())
}
fn read(&self) -> Result<String> {
let path = self.as_ref();
fs::read_to_string(path).map_err(|e| {
anyhow::anyhow!(
"Failed to read file: {}, {}",
path.display().to_string().underline(),
e.to_string()
)
})
}
}
pub trait Prefix: AsRef<Path> + Sized {
fn is_sub(&self, path: impl AsRef<Path>) -> Result<bool>;
fn prefix(&mut self, prefix: impl AsRef<Path>);
}
impl Prefix for PathBuf {
fn is_sub(&self, path: impl AsRef<Path>) -> Result<bool> {
let ancestor = fs::canonicalize(self)?;
let sub = fs::canonicalize(path)?;
Ok(sub
.as_os_str()
.to_string_lossy()
.to_string()
.contains(ancestor.as_os_str().to_string_lossy().to_string().as_str()))
}
fn prefix(&mut self, prefix: impl AsRef<Path>) {
if self.is_relative() {
*self = prefix.as_ref().join(&self)
}
}
}
pub fn markdown(content: &str) -> String {
let mut html = String::new();
html::push_html(&mut html, Parser::new_ext(content, Options::all()));
html
}
pub fn find_proj(base: &Path) -> Result<PathBuf> {
if base.join("sonata.toml").exists() {
return Ok(base.to_path_buf());
}
Ok(etc::find_up("sonata.toml")?
.parent()
.ok_or_else(|| anyhow!("Could not find sonata.toml"))?
.to_path_buf())
}