dim_screen/
opts.rs

1use std::path::{Path, PathBuf};
2
3use anyhow::{anyhow, Result};
4use clap::{CommandFactory, Parser, ValueEnum};
5use clap_complete::{generate_to, Shell};
6use serde::Deserialize;
7
8use crate::{consts::DEFAULT_ALPHA, consts::DEFAULT_DURATION};
9
10#[derive(Debug, Deserialize, Parser)]
11#[command(author, version, about)]
12pub struct DimOpts {
13    #[arg(
14        short,
15        long,
16        help = format!("Duration in seconds, 0 is infinite, [default: {DEFAULT_DURATION}]")
17    )]
18    pub duration: Option<u64>,
19
20    #[arg(
21        short,
22        long,
23        help = format!("0.0 is transparent, 1.0 is opaque. When opaque, cursor will be hidden. [default: {DEFAULT_ALPHA}]")
24    )]
25    pub alpha: Option<f32>,
26
27    #[arg(
28        short,
29        long,
30        help = "Make dim ignore input, passing it to lower surfaces. (You probably want to use `-d 0` with this)"
31    )]
32    #[serde(default)]
33    pub passthrough: bool,
34
35    #[serde(skip)]
36    #[arg(long, value_name = "PATH", help = "Generate completions at given path")]
37    pub gen_completions: Option<PathBuf>,
38
39    #[serde(skip)]
40    #[arg(short, long, value_name = "PATH", help = "Use config at path")]
41    pub config: Option<PathBuf>,
42}
43
44impl DimOpts {
45    pub fn generate_completions(dir: &Path) -> anyhow::Result<()> {
46        let mut cli = Self::command();
47
48        for &shell in Shell::value_variants() {
49            let comp_file = generate_to(shell, &mut cli, "dim", dir)?;
50            println!("Generated completion for {shell} at {comp_file:?}");
51        }
52
53        Ok(())
54    }
55
56    /// Merge other onto self, with other's values taking precedent
57    pub fn merge_onto_self(self, other: DimOpts) -> Self {
58        Self {
59            duration: other.duration.or(self.duration),
60            alpha: other.alpha.or(self.alpha),
61            passthrough: self.passthrough || other.passthrough,
62
63            ..self
64        }
65    }
66
67    /// Validate that the received values are within our limits, should be called before using this
68    /// object.
69    pub fn validate(&self) -> Result<()> {
70        if let Some(alpha) = self.alpha {
71            if !(0.0..=1.0).contains(&alpha) {
72                return Err(anyhow!("Alpha can only be from 0.0 to 1.0 inclusive."));
73            }
74        }
75
76        Ok(())
77    }
78
79    /// Get user desired alpha or the default value.
80    pub fn alpha(&self) -> f32 {
81        self.alpha.unwrap_or(DEFAULT_ALPHA)
82    }
83
84    /// Get user desired duration or the default value.
85    pub fn duration(&self) -> u64 {
86        self.duration.unwrap_or(DEFAULT_DURATION)
87    }
88}