Skip to content

Commit

Permalink
WIP: Added a ignore_remaining cli option and a save_config function. …
Browse files Browse the repository at this point in the history
…Now need to add all the errors to the igore and ignore_word_pairs and save_config
  • Loading branch information
ryanpeach committed Jan 5, 2025
1 parent 447e76a commit 02e2ceb
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 29 deletions.
139 changes: 115 additions & 24 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub enum NewConfigError {
/// Used to reconcile the two
#[derive(Builder)]
pub struct Config {
file_config: file::Config,
cli_config: cli::Config,
/// See [`self::cli::Config::pages_directory`]
pub pages_directory: PathBuf,
/// See [`self::cli::Config::other_directories`]
Expand Down Expand Up @@ -72,6 +74,9 @@ pub struct Config {
/// See [`self::file::Config::ignore_word_pairs`]
#[builder(default = vec![])]
pub ignore_word_pairs: Vec<(String, String)>,
/// See [`self::cli::Config::ignore_remaining`]
#[builder(default = false)]
pub ignore_remaining: bool,
}

/// Things which implement the partial config trait
Expand All @@ -95,40 +100,94 @@ pub trait Partial {
fn fix(&self) -> Option<bool>;
fn allow_dirty(&self) -> Option<bool>;
fn ignore_word_pairs(&self) -> Option<Vec<(String, String)>>;
fn ignore_remaining(&self) -> Option<bool>;
}

/// Now we implement a combine function for patrial configs which
/// iterates over the partials and if they have a Some field they use that field in the final
/// config.
///
/// Note: This makes last elements in the input slice first priority
fn combine_partials(partials: &[&dyn Partial]) -> Result<Config, NewConfigError> {
fn combine_partials(
file_config: &file::Config,
cli_config: &cli::Config,
) -> Result<Config, NewConfigError> {
Ok(Config::builder()
.maybe_ngram_size(partials.iter().find_map(|p| p.ngram_size()))
.maybe_boundary_pattern(partials.iter().find_map(|p| p.boundary_pattern()))
.maybe_filename_spacing_pattern(partials.iter().find_map(|p| p.filename_spacing_pattern()))
.maybe_filename_match_threshold(partials.iter().find_map(|p| p.filename_match_threshold()))
.maybe_exclude(partials.iter().find_map(|p| p.exclude()))
.maybe_filename_to_alias(match partials.iter().find_map(|p| p.filename_to_alias()) {
Some(Ok(pair)) => Some(pair),
Some(Err(e)) => return Err(NewConfigError::ReplacePairCompilationError(e)),
None => None,
.file_config(file_config.clone())
.cli_config(cli_config.clone())
.maybe_ngram_size(cli_config.ngram_size().or(file_config.ngram_size()))
.maybe_boundary_pattern(
cli_config
.boundary_pattern()
.or(file_config.boundary_pattern()),
)
.maybe_filename_spacing_pattern(
cli_config
.filename_spacing_pattern()
.or(file_config.filename_spacing_pattern()),
)
.maybe_filename_match_threshold(
cli_config
.filename_match_threshold()
.or(file_config.filename_match_threshold()),
)
.maybe_exclude(cli_config.exclude().or(file_config.exclude()))
.maybe_filename_to_alias({
match (
cli_config.filename_to_alias(),
file_config.filename_to_alias(),
) {
(Some(Ok(cli)), None) => Some(cli),
(None, Some(Ok(file))) => Some(file),
(Some(Ok(cli)), Some(Ok(_file))) => Some(cli),
(_, Some(Err(e))) | (Some(Err(e)), _) => {
return Err(NewConfigError::ReplacePairCompilationError(e))
}
(None, None) => {
unreachable!("There should always be a default, or at least empty strings...")
}
}
})
.maybe_alias_to_filename(match partials.iter().find_map(|p| p.alias_to_filename()) {
Some(Ok(pair)) => Some(pair),
Some(Err(e)) => return Err(NewConfigError::ReplacePairCompilationError(e)),
None => None,
.maybe_alias_to_filename({
match (
cli_config.alias_to_filename(),
file_config.alias_to_filename(),
) {
(Some(Ok(cli)), None) => Some(cli),
(None, Some(Ok(file))) => Some(file),
(Some(Ok(cli)), Some(Ok(_file))) => Some(cli),
(_, Some(Err(e))) | (Some(Err(e)), _) => {
return Err(NewConfigError::ReplacePairCompilationError(e))
}
(None, None) => {
unreachable!("There should always be a default, or at least empty strings...")
}
}
})
.maybe_fix(partials.iter().find_map(|p| p.fix()))
.maybe_allow_dirty(partials.iter().find_map(|p| p.allow_dirty()))
.maybe_fix(cli_config.fix().or(file_config.fix()))
.maybe_allow_dirty(cli_config.allow_dirty().or(file_config.allow_dirty()))
.pages_directory(
partials
.iter()
.find_map(|p| p.pages_directory())
.ok_or(NewConfigError::PagesDirectoryMissing)?,
cli_config
.pages_directory()
.or(file_config.pages_directory())
.expect("A default is set"),
)
.maybe_other_directories(Some(
cli_config
.other_directories()
.or(file_config.other_directories())
.expect("A default is set"),
))
.maybe_ignore_word_pairs(
cli_config
.ignore_word_pairs()
.or(file_config.ignore_word_pairs()),
)
.maybe_ignore_remaining(
cli_config
.ignore_remaining()
.or(file_config.ignore_remaining()),
)
.maybe_other_directories(partials.iter().find_map(|p| p.other_directories()))
.maybe_ignore_word_pairs(partials.iter().find_map(|p| p.ignore_word_pairs()))
.build())
}

Expand Down Expand Up @@ -157,15 +216,47 @@ impl Config {
};

// CLI has priority over file by being last
combine_partials(&[&file, &cli])
let mut out = combine_partials(&file, &cli);

// Match on a ref to out, so we do NOT move the config out of `out`
if let Ok(ref mut config) = out {
config.cli_config = cli;
config.file_config = file;
}

// Now `out` is still valid (unchanged type), so we can return it
out
}

/// Legacy directories function
/// Gets all the directories into one vec
#[must_use]
pub fn directories(&self) -> Vec<PathBuf> {
let mut out = vec![self.pages_directory.clone()];
let mut out = Vec::new();
out.push(self.pages_directory.clone());
out.extend(self.other_directories.clone());
out
}

pub fn save_config(&self) -> Result<(), SaveConfigError> {
let toml_str =
toml::to_string(&self.file_config).map_err(|e| SaveConfigError::Toml { source: e })?;
std::fs::write(self.cli_config.config_path.clone(), toml_str)
.map_err(|e| SaveConfigError::Io { source: e })?;
Ok(())
}
}

#[derive(thiserror::Error, Debug, Diagnostic)]
pub enum SaveConfigError {
#[error(transparent)]
Io {
#[backtrace]
source: io::Error,
},
#[error(transparent)]
Toml {
#[backtrace]
source: toml::ser::Error,
},
}
9 changes: 8 additions & 1 deletion src/config/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{

use super::Partial;

#[derive(Parser, Default)]
#[derive(Parser, Default, Clone)]
#[command(version, about, long_about = None)]
pub(super) struct Config {
/// The pages directory is the directory where pages are named for their alias
Expand Down Expand Up @@ -60,6 +60,10 @@ pub(super) struct Config {
/// the git repo has uncommitted changes
#[clap(long = "allow-dirty")]
pub allow_dirty: bool,

/// Ignore remaining errors by adding them to the config
#[clap(long = "ignore-remaining")]
pub ignore_remaining: bool,
}

impl Partial for Config {
Expand Down Expand Up @@ -113,4 +117,7 @@ impl Partial for Config {
fn ignore_word_pairs(&self) -> Option<Vec<(String, String)>> {
None
}
fn ignore_remaining(&self) -> Option<bool> {
Some(self.ignore_remaining)
}
}
27 changes: 24 additions & 3 deletions src/config/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use crate::{
sed::{ReplacePair, ReplacePairCompilationError},
};

use super::{NewConfigError, Partial};
use super::{Config as MasterConfig, NewConfigError, Partial};

#[derive(Serialize, Deserialize, Debug, Default)]
pub(super) struct Config {
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Config {
/// See [`super::cli::Config::pages_directory`]
pub pages_directory: PathBuf,

Expand Down Expand Up @@ -65,6 +65,23 @@ impl Config {
}
}

impl From<MasterConfig> for Config {
fn from(value: MasterConfig) -> Self {
Self {
pages_directory: value.pages_directory,
other_directories: value.other_directories,
ngram_size: Some(value.ngram_size),
boundary_pattern: Some(value.boundary_pattern),
filename_spacing_pattern: Some(value.filename_spacing_pattern),
filename_match_threshold: Some(value.filename_match_threshold),
exclude: value.exclude.into_iter().map(|x| x.0).collect(),
ignore_word_pairs: value.ignore_word_pairs,
alias_to_filename: value.alias_to_filename.into(),
filename_to_alias: value.filename_to_alias.into(),
}
}
}

impl Partial for Config {
fn pages_directory(&self) -> Option<PathBuf> {
Some(self.pages_directory.clone())
Expand Down Expand Up @@ -147,4 +164,8 @@ impl Partial for Config {
Some(self.ignore_word_pairs.clone())
}
}

fn ignore_remaining(&self) -> Option<bool> {
None
}
}
2 changes: 1 addition & 1 deletion src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub enum ThirdPassReport {
/// A Reports error code, usually like `asdf::asdf::asdf`
/// Uniquely identifies a violation of a rule, and can be deduped by Eq
#[derive(Debug, Constructor, PartialEq, Eq, PartialOrd, Ord, Clone, From, Into)]
pub struct ErrorCode(String);
pub struct ErrorCode(pub String);

/// All reports should have a code that can be human readable
/// Codes's should also be useful to deduplicate errors before presenting them to the user
Expand Down
10 changes: 10 additions & 0 deletions src/sed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ where
_u: std::marker::PhantomData<U>,
}

impl<T, U> From<ReplacePair<T, U>> for (String, String)
where
T: ToString + From<String>,
U: ToString + From<String>,
{
fn from(val: ReplacePair<T, U>) -> Self {
(val.from.as_str().to_owned(), val.to.as_str().to_owned())
}
}

impl<T, U> ReplacePair<T, U>
where
T: ToString + From<String>,
Expand Down

0 comments on commit 02e2ceb

Please sign in to comment.