standout 12.0.1

Styled CLI template rendering with automatic terminal detection
pub use standout_dispatch::{
    emits_events, AppFailure, Artifact, ArtifactDestination, ArtifactReceipt, ArtifactRun,
    CommandContext, ContractSurface, Delivery, Diagnostic, DiagnosticKind, DiagnosticPosition,
    DiagnosticRange, DispatchResult, EmitError, Envelope, EventSink, EventsFnHandler, ExitStatus,
    Extensions, ExternalFailure, FnHandler, Handler, HandlerOutcome, HandlerResult,
    InvalidAppStatus, InvalidExternalStatus, NoEvents, Output, OutputKind, Results, RunError,
    RunErrorKind, RunOutput, RunRecorder, Severity, StreamCapture, StreamSink, SuccessKind,
    Summary, SummaryResult,
};

use standout_input::{InputSourceKind, Inputs, MissingInput};

use crate::cli::config::{MissingConfig, ResolvedApp};
use crate::cli::questionnaire::QUESTIONNAIRE_INPUT_NAME;

pub trait CommandContextInput {
    fn input<T: 'static>(&self, name: &str) -> Result<&T, MissingInput>;

    fn questionnaire<T: 'static>(&self) -> Result<&T, MissingInput>;

    fn config<C: 'static>(&self) -> Result<&C, MissingConfig>;

    fn install_config<C: 'static>(&mut self, config: C);

    fn input_source(&self, name: &str) -> Option<InputSourceKind>;

    fn inputs(&self) -> Option<&Inputs>;

    fn input_sources(&self) -> &standout_input::InputSources;

    fn warn(&self, message: impl Into<String>);
}

impl CommandContextInput for CommandContext {
    fn input<T: 'static>(&self, name: &str) -> Result<&T, MissingInput> {
        match self.extensions.get::<Inputs>() {
            Some(bag) => bag.get_required::<T>(name),
            None => Err(MissingInput::NotRegistered {
                name: name.to_string(),
            }),
        }
    }

    fn questionnaire<T: 'static>(&self) -> Result<&T, MissingInput> {
        self.input(QUESTIONNAIRE_INPUT_NAME)
    }

    fn config<C: 'static>(&self) -> Result<&C, MissingConfig> {
        self.extensions
            .get::<ResolvedApp<C>>()
            .map(|resolved| &resolved.0)
            .ok_or(MissingConfig {
                type_name: std::any::type_name::<C>(),
            })
    }

    fn install_config<C: 'static>(&mut self, config: C) {
        self.extensions.insert(ResolvedApp(config));
    }

    fn input_source(&self, name: &str) -> Option<InputSourceKind> {
        self.extensions.get::<Inputs>()?.source_of(name)
    }

    fn inputs(&self) -> Option<&Inputs> {
        self.extensions.get::<Inputs>()
    }

    fn input_sources(&self) -> &standout_input::InputSources {
        self.extensions
            .get::<standout_input::InputSources>()
            .expect("InputSources are inserted at the run/dispatch edge")
    }

    fn warn(&self, message: impl Into<String>) {
        if let Some(buffer) = self
            .extensions
            .get::<standout_render::warnings::WarningBuffer>()
        {
            buffer.push(message);
        }
    }
}