skyspell_core 6.0.0

skyspell core library
Documentation
use std::path::{Path, PathBuf};

use anyhow::{Context, Result, anyhow};
use ignore::{Walk, WalkBuilder};
use serde::{Deserialize, Serialize};

use crate::{IgnoreStore, SkipFile, global_path};

pub const SKYSPELL_LOCAL_IGNORE: &str = "skyspell-ignore.toml";

#[derive(Debug, Clone)]
pub struct Project {
    path: PathBuf,
    skip_file: SkipFile,
}

impl Project {
    pub fn new(path: &Path) -> Result<Self> {
        let skip_file = SkipFile::new(path)?;
        let path = std::path::absolute(path)
            .with_context(|| format!("Could not make path {path:?} absolute "))?;
        Ok(Self { path, skip_file })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn path_string(&self) -> String {
        self.path.to_string_lossy().into_owned()
    }

    pub fn new_project_file<P: AsRef<Path>>(&self, path: P) -> Result<ProjectFile> {
        ProjectFile::new(self, path.as_ref())
    }

    pub fn ignore_path(&self) -> PathBuf {
        let path = self.path();
        path.join(SKYSPELL_LOCAL_IGNORE)
    }

    pub fn ignore_store(&self) -> Result<IgnoreStore> {
        let local_path = self.path.join(SKYSPELL_LOCAL_IGNORE);
        let global_path = global_path()?;

        IgnoreStore::load(global_path, local_path)
    }

    pub fn skip_file(&self) -> &SkipFile {
        &self.skip_file
    }

    pub fn walk(&self) -> Result<Walk> {
        Ok(WalkBuilder::new(self.path()).build())
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ProjectFile {
    name: String,
    extension: Option<String>,
    full_path: PathBuf,
}

impl ProjectFile {
    pub fn new(project: &Project, source_path: &Path) -> Result<Self> {
        let extension = source_path
            .extension()
            .map(|x| x.to_string_lossy().into_owned());

        let project_path = project.path();
        let full_path = std::path::absolute(source_path).with_context(|| {
            anyhow!(
                "Could not make relative path absolute: {}",
                source_path.display()
            )
        })?;
        let relative_path = pathdiff::diff_paths(&full_path, project_path).ok_or_else(|| {
            anyhow!(
                "Could not diff paths '{}' and '{}'",
                full_path.display(),
                project_path.display(),
            )
        })?;
        let name = relative_path.to_string_lossy().into_owned();
        let name = name.replace("\\", "/");
        Ok(Self {
            name,
            extension,
            full_path,
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn extension(&self) -> Option<&str> {
        self.extension.as_deref()
    }

    pub fn full_path(&self) -> &Path {
        &self.full_path
    }
}