Skip to content

Commit

Permalink
sqf: event handlers (#702)
Browse files Browse the repository at this point in the history
  • Loading branch information
BrettMayson authored Jun 10, 2024
1 parent 57b71ce commit b33d492
Show file tree
Hide file tree
Showing 28 changed files with 718 additions and 65 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ future_incompatible = "warn"
nonstandard_style = "warn"

[workspace.dependencies]
arma3-wiki = "0.1.18"
arma3-wiki = "0.2.4"
byteorder = "1.5.0"
chumsky = "0.9.3"
clap = "4.5.4"
Expand Down
1 change: 1 addition & 0 deletions bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ hemtt-signing = { path = "../libs/signing", version = "1.0.0" }
hemtt-sqf = { path = "../libs/sqf", version = "1.0.0" }
hemtt-workspace = { path = "../libs/workspace", version = "1.0.0" }

arma3-wiki = { workspace = true }
clap = { workspace = true }
dialoguer = "0.11.0"
fs_extra = "1.3.0"
Expand Down
2 changes: 1 addition & 1 deletion bin/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub fn executor(ctx: Context, matches: &ArgMatches) -> Executor {
if matches.get_one::<bool>("no-rap") != Some(&true) {
executor.add_module(Box::<Rapifier>::default());
}
executor.add_module(Box::new(SQFCompiler { compile: expsqfc }));
executor.add_module(Box::new(SQFCompiler::new(expsqfc)));
#[cfg(not(target_os = "macos"))]
if !expsqfc {
executor.add_module(Box::<ArmaScriptCompiler>::default());
Expand Down
2 changes: 1 addition & 1 deletion bin/src/commands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ pub fn context(matches: &ArgMatches, launch_optionals: &[String]) -> Result<Exec

executor.add_module(Box::<Hooks>::default());
executor.add_module(Box::<Rapifier>::default());
executor.add_module(Box::new(SQFCompiler { compile: expsqfc }));
executor.add_module(Box::new(SQFCompiler::new(expsqfc)));
#[cfg(not(target_os = "macos"))]
if !expsqfc {
executor.add_module(Box::<ArmaScriptCompiler>::default());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@ impl Code for LaunchConfigNotFound {
if self.similar.is_empty() {
None
} else {
Some(format!(
"did you mean `{}`?",
self.similar
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<String>>()
.join("`, `")
))
Some(format!("did you mean `{}`?", self.similar.join("`, `")))
}
}

Expand Down
1 change: 1 addition & 0 deletions bin/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod release;
pub mod script;
pub mod utils;
pub mod value;
pub mod wiki;
27 changes: 27 additions & 0 deletions bin/src/commands/wiki.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use clap::{ArgMatches, Command};
use hemtt_sqf::parser::database::Database;

use crate::{error::Error, report::Report};

#[must_use]
pub fn cli() -> Command {
Command::new("wiki")
.about("Manage the Arma 3 wiki")
.subcommand(
Command::new("force-pull")
.about("Force pull the wiki, if updates you need have been pushed very recently"),
)
}

/// Execute the wiki command
///
/// # Errors
/// [`Error`] depending on the modules
///
/// # Panics
/// If a name is not provided, but this is usually handled by clap
pub fn execute(_matches: &ArgMatches) -> Result<Report, Error> {
// TODO right now just assumes force-pull since that's the only subcommand
let _ = Database::empty(true);
Ok(Report::new())
}
4 changes: 4 additions & 0 deletions bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub fn cli() -> Command {
.subcommand(commands::script::cli())
.subcommand(commands::utils::cli())
.subcommand(commands::value::cli())
.subcommand(commands::wiki::cli())
.arg(
clap::Arg::new("threads")
.global(true)
Expand Down Expand Up @@ -139,6 +140,9 @@ pub fn execute(matches: &ArgMatches) -> Result<(), Error> {
Some(("value", matches)) => commands::value::execute(matches)
.map_err(std::convert::Into::into)
.map(Some),
Some(("wiki", matches)) => commands::wiki::execute(matches)
.map_err(std::convert::Into::into)
.map(Some),
_ => unreachable!(),
};
if let Some(report) = report? {
Expand Down
114 changes: 110 additions & 4 deletions bin/src/modules/sqf.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::{
atomic::{AtomicU16, Ordering},
Arc,
};

use hemtt_common::version::Version;
use hemtt_preprocessor::Processor;
use hemtt_sqf::{
analyze::analyze,
parser::{database::Database, ParserError},
};
use hemtt_workspace::reporting::{Code, Diagnostic, Severity};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};

use crate::{context::Context, error::Error, report::Report};
Expand All @@ -14,13 +19,29 @@ use super::Module;
#[derive(Default)]
pub struct SQFCompiler {
pub compile: bool,
pub database: Option<Database>,
}

impl SQFCompiler {
#[must_use]
pub const fn new(compile: bool) -> Self {
Self {
compile,
database: None,
}
}
}

impl Module for SQFCompiler {
fn name(&self) -> &'static str {
"SQF"
}

fn init(&mut self, ctx: &Context) -> Result<Report, Error> {
self.database = Some(Database::a3_with_workspace(ctx.workspace_path(), false)?);
Ok(Report::new())
}

#[allow(clippy::too_many_lines)]
fn pre_build(&self, ctx: &Context) -> Result<Report, Error> {
let mut report = Report::new();
Expand All @@ -37,7 +58,7 @@ impl Module for SQFCompiler {
}
}
}
let database = Database::a3_with_workspace(ctx.workspace_path())?;
let database = self.database.as_ref().expect("database not initialized");
let reports = entries
.par_iter()
.map(|(addon, entry)| {
Expand All @@ -47,10 +68,10 @@ impl Module for SQFCompiler {
for warning in processed.warnings() {
report.warn(warning.clone());
}
match hemtt_sqf::parser::run(&database, &processed) {
match hemtt_sqf::parser::run(database, &processed) {
Ok(sqf) => {
let (warnings, errors) =
analyze(&sqf, Some(ctx.config()), &processed, Some(addon), &database);
analyze(&sqf, Some(ctx.config()), &processed, Some(addon), database);
for warning in warnings {
report.warn(warning);
}
Expand Down Expand Up @@ -105,4 +126,89 @@ impl Module for SQFCompiler {
);
Ok(report)
}

fn post_build(&self, ctx: &Context) -> Result<Report, crate::Error> {
let mut report = Report::new();
let mut required_version = Version::new(0, 0, 0, None);
let mut required_by = Vec::new();
for addon in ctx.addons() {
let addon_version = addon.build_data().required_version();
if let Some((version, _, _)) = addon_version {
if version > required_version {
required_version = version;
required_by = vec![addon.name().to_string()];
} else if version == required_version {
required_by.push(addon.name().to_string());
}
}
}

let database = self.database.as_ref().expect("database not initialized");

let wiki_version = arma3_wiki::model::Version::new(
u8::try_from(required_version.major()).unwrap_or_default(),
u8::try_from(required_version.minor()).unwrap_or_default(),
);
if database.wiki().version() < &wiki_version {
report.warn(Arc::new(RequiresFutureVersion::new(
wiki_version,
required_by,
*database.wiki().version(),
)));
}

Ok(report)
}
}

pub struct RequiresFutureVersion {
required_version: arma3_wiki::model::Version,
required_by: Vec<String>,
wiki_version: arma3_wiki::model::Version,
}
impl Code for RequiresFutureVersion {
fn ident(&self) -> &'static str {
"BSW1"
}

fn severity(&self) -> Severity {
Severity::Warning
}

fn message(&self) -> String {
format!(
"Required version `{}` is higher than the current stable `{}`",
self.required_version, self.wiki_version
)
}

fn note(&self) -> Option<String> {
Some(format!(
"addons requiring version `{}`: {}",
self.required_version,
self.required_by.join(", ")
))
}

fn help(&self) -> Option<String> {
Some("Learn about the `development` branch at `https://community.bistudio.com/wiki/Arma_3:_Steam_Branches`".to_string())
}

fn diagnostic(&self) -> Option<Diagnostic> {
Some(Diagnostic::simple(self))
}
}

impl RequiresFutureVersion {
pub fn new(
required_version: arma3_wiki::model::Version,
required_by: Vec<String>,
wiki_version: arma3_wiki::model::Version,
) -> Self {
Self {
required_version,
required_by,
wiki_version,
}
}
}
2 changes: 1 addition & 1 deletion hls/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use arma3_wiki::Wiki;

fn main() {
let wiki = Wiki::load();
let wiki = Wiki::load(true);

let mut flow = Vec::with_capacity(500);
let mut commands = Vec::with_capacity(3000);
Expand Down
2 changes: 1 addition & 1 deletion hls/src/sqf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl SqfCache {
return;
}
};
let database = match Database::a3_with_workspace(workspace.root()) {
let database = match Database::a3_with_workspace(workspace.root(), false) {
Ok(database) => database,
Err(e) => {
error!("Failed to create database {:?}", e);
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod sign_version;
pub use sign_version::BISignVersion;

#[must_use]
/// Returns up to 3 similar values from a haystack.
pub fn similar_values<'a>(search: &str, haystack: &'a [&str]) -> Vec<&'a str> {
let mut similar = haystack
.iter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl Code for FunctionCallArgumentCount {
None
} else {
Some(format!(
"did you mean `{}`",
"did you mean `{}`?",
self.similar
.iter()
.map(std::string::ToString::to_string)
Expand Down
6 changes: 5 additions & 1 deletion libs/sqf/src/analyze/codes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
pub mod sae1_require_version;
pub mod sae1_require_version_command;
pub mod sae2_require_version_event;

pub mod saw1_unknown_event;
pub mod saw2_wrong_event_command;

pub mod saa1_if_assign;
pub mod saa2_find_in_str;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ use hemtt_workspace::{
WorkspacePath,
};

pub struct InsufficientRequiredVersion {
pub struct InsufficientRequiredVersionCommand {
command: String,
span: Range<usize>,
version: Version,
required: (Version, WorkspacePath, Range<usize>),
required: (Option<Version>, WorkspacePath, Range<usize>),
stable: Version,

diagnostic: Option<Diagnostic>,
}

impl Code for InsufficientRequiredVersion {
impl Code for InsufficientRequiredVersionCommand {
fn ident(&self) -> &'static str {
"SAE1"
}
Expand Down Expand Up @@ -48,7 +48,7 @@ impl Code for InsufficientRequiredVersion {
}
}

impl InsufficientRequiredVersion {
impl InsufficientRequiredVersionCommand {
#[must_use]
pub fn new(
command: String,
Expand All @@ -62,7 +62,13 @@ impl InsufficientRequiredVersion {
command,
span,
version,
required,
required: {
if required.0.major() == 0 && required.0.minor() == 0 {
(None, required.1, required.2)
} else {
(Some(required.0), required.1, required.2)
}
},
stable,

diagnostic: None,
Expand All @@ -76,7 +82,10 @@ impl InsufficientRequiredVersion {
};
self.diagnostic = Some(diag.with_label(
Label::secondary(self.required.1.clone(), self.required.2.clone()).with_message(
format!("CfgPatch only requires version {}", self.required.0),
self.required.0.map_or_else(
|| "CfgPatch doesn't specify `requiredVersion`".to_string(),
|required| format!("CfgPatch requires version {required}"),
),
),
));
self
Expand Down
Loading

0 comments on commit b33d492

Please sign in to comment.