knave 0.9.17

A small Lisp for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use std::path::{Path, PathBuf};

use super::exit_status::ExitStatus;
use super::located_project::LocatedProject;
use super::program_file::ProgramFile;
use super::standard_error::StandardError;
use super::terminal::Terminal;
use crate::language::Language;

pub struct LocatedProgram {
    file: ProgramFile,
    project: Option<LocatedProject>,
}

impl LocatedProgram {
    pub fn locate(file: Option<PathBuf>, terminal: &Terminal) -> Result<Self, ExitStatus> {
        match file {
            Some(file) => Self::of_file(file, terminal),
            None => Self::of_working_directory(terminal),
        }
    }

    fn of_file(file: PathBuf, terminal: &Terminal) -> Result<Self, ExitStatus> {
        let project = LocatedProject::search_from(&ProgramFile::directory_of(&file), terminal)?;
        let file = match &project {
            Some(project) => project.file_within(file),
            None => ProgramFile::beside_itself(file),
        };
        Ok(Self { file, project })
    }

    fn of_working_directory(terminal: &Terminal) -> Result<Self, ExitStatus> {
        let working_directory = Path::new(Terminal::WORKING_DIRECTORY);
        match LocatedProject::search_from(working_directory, terminal)? {
            Some(project) => Ok(Self {
                file: project.entry(),
                project: Some(project),
            }),
            None => Err(Self::report_no_program()),
        }
    }

    pub fn file(&self) -> &ProgramFile {
        &self.file
    }

    pub fn into_file(self) -> ProgramFile {
        self.file
    }

    pub fn entry_project(&self) -> Option<&LocatedProject> {
        self.project
            .as_ref()
            .filter(|project| project.is_entry(&self.file))
    }

    fn report_no_program() -> ExitStatus {
        StandardError::write_line(format_args!(
            "error: no file given, and no `{}` in this directory or a parent\n\
             help: name a file, or run the command inside a project",
            Language::project_file_name()
        ));
        ExitStatus::UsageError
    }
}