<commit_before>use self::format::reformat_doc;
use crate::{
    analysis::{self, namespaces::MAIN},
    case::CaseExt,
    config::gobjects::GObject,
    env::Env,
    file_saver::save_to_file,
    library::{self, Type as LType, *},
    nameutil,
    traits::*,
    version::Version,
};
use log::{error, info};
use once_cell::sync::Lazy;
use regex::{Captures, Regex};
use std::{
    borrow::Cow,
    collections::{BTreeSet, HashSet},
    io::{Result, Write},
};
use stripper_lib::{write_file_name, write_item_doc, Type as SType, TypeStruct};

mod format;

// A list of C parameters that are not used directly by the Rust bindings
const IGNORED_C_FN_PARAMS: [&str; 6] = [
    "user_data",
    "user_destroy",
    "destroy_func",
    "dnotify",
    "destroy",
    "user_data_free_func",
];

trait ToStripperType {
    fn to_stripper_type(&self) -> TypeStruct;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident, $useless:expr) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(
                    SType::$enum_var,
                    &format!("connect_{}", nameutil::signal_to_snake(&self.name)),
                )
            }
        }
    };
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }
        }
    };
}

trait FunctionLikeType {
    fn doc(&self) -> &Option<String>;
    fn doc_deprecated(&self) -> &Option<String>;
    fn ret(&self) -> &Parameter;
    fn parameters(&self) -> &[Parameter];
    fn version(&self) -> &Option<Version>;
    fn deprecated_version(&self) -> &Option<Version>;
}

macro_rules! impl_function_like_type {
    ($ty:ident) => {
        impl FunctionLikeType for $ty {
            fn doc(&self) -> &Option<String> {
                &self.doc
            }
            fn doc_deprecated(&self) -> &Option<String> {
                &self.doc_deprecated
            }
            fn ret(&self) -> &Parameter {
                &self.ret
            }
            fn parameters(&self) -> &[Parameter] {
                &self.parameters
            }
            fn version(&self) -> &Option<Version> {
                &self.version
            }
            fn deprecated_version(&self) -> &Option<Version> {
                &self.deprecated_version
            }
        }
    };
}

impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Struct);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Signal, Fn, false);

impl_function_like_type!(Function);
impl_function_like_type!(Signal);

pub fn generate(env: &Env) {
    info!("Generating documentation {:?}", env.config.doc_target_path);
    save_to_file(&env.config.doc_target_path, env.config.make_backup, |w| {
        generate_doc(w, env)
    });
}

#[allow(clippy::type_complexity)]
fn generate_doc(w: &mut dyn Write, env: &Env) -> Result<()> {
    write_file_name(w, None)?;
    let mut generators: Vec<(&str, Box<dyn Fn(&mut dyn Write, &Env) -> Result<()>>)> = Vec::new();

    for info in env.analysis.objects.values() {
        if info.type_id.ns_id == MAIN && !env.is_totally_deprecated(info.deprecated_version) {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_object_doc(w, e, info)),
            ));
        }
    }

    for info in env.analysis.records.values() {
        if info.type_id.ns_id == MAIN && !env.is_totally_deprecated(info.deprecated_version) {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_record_doc(w, e, info)),
            ));
        }
    }

    for (tid, type_) in env.library.namespace_types(MAIN) {
        if let LType::Enumeration(enum_) = type_ {
            if !env
                .config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
                && !env.is_totally_deprecated(enum_.deprecated_version)
            {
                generators.push((
                    &enum_.name[..],
                    Box::new(move |w, e| create_enum_doc(w, e, enum_)),
                ));
            }
        } else if let LType::Bitfield(bitfield) = type_ {
            if !env
                .config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
                && !env.is_totally_deprecated(bitfield.deprecated_version)
            {
                generators.push((
                    &bitfield.name[..],
                    Box::new(move |w, e| create_bitfield_doc(w, e, bitfield)),
                ));
            }
        }
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);

    if let Some(ref global_functions) = env.analysis.global_functions {
        let functions = ns
            .functions
            .iter()
            .filter(|f| f.kind == library::FunctionKind::Global);

        for function in functions {
            if let Some(ref c_identifier) = function.c_identifier {
                let fn_new_name = (&global_functions.functions)
                    .iter()
                    .find(move |f| &f.glib_name == c_identifier)
                    .and_then(|analysed_f| analysed_f.new_name.clone());
                create_fn_doc(w, env, function, None, fn_new_name)?;
            }
        }
    }

    let symbols = env.symbols.borrow();
    for constant in &ns.constants {
        // strings are mapped to a static
        let ty = if constant.c_type == "gchar*" {
            SType::Static
        } else {
            SType::Const
        };
        let ty_id = TypeStruct::new(ty, &constant.name);
        write_item_doc(w, &ty_id, |w| {
            if let Some(ref doc) = constant.doc {
                writeln!(w, "{}", reformat_doc(doc, &symbols, &constant.name))?;
            }
            Ok(())
        })?;
    }
<commit_msg>docs: fix a missing param due to not rebasing #1151<commit_after>use self::format::reformat_doc;
use crate::{
    analysis::{self, namespaces::MAIN},
    case::CaseExt,
    config::gobjects::GObject,
    env::Env,
    file_saver::save_to_file,
    library::{self, Type as LType, *},
    nameutil,
    traits::*,
    version::Version,
};
use log::{error, info};
use once_cell::sync::Lazy;
use regex::{Captures, Regex};
use std::{
    borrow::Cow,
    collections::{BTreeSet, HashSet},
    io::{Result, Write},
};
use stripper_lib::{write_file_name, write_item_doc, Type as SType, TypeStruct};

mod format;

// A list of C parameters that are not used directly by the Rust bindings
const IGNORED_C_FN_PARAMS: [&str; 6] = [
    "user_data",
    "user_destroy",
    "destroy_func",
    "dnotify",
    "destroy",
    "user_data_free_func",
];

trait ToStripperType {
    fn to_stripper_type(&self) -> TypeStruct;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident, $useless:expr) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(
                    SType::$enum_var,
                    &format!("connect_{}", nameutil::signal_to_snake(&self.name)),
                )
            }
        }
    };
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }
        }
    };
}

trait FunctionLikeType {
    fn doc(&self) -> &Option<String>;
    fn doc_deprecated(&self) -> &Option<String>;
    fn ret(&self) -> &Parameter;
    fn parameters(&self) -> &[Parameter];
    fn version(&self) -> &Option<Version>;
    fn deprecated_version(&self) -> &Option<Version>;
}

macro_rules! impl_function_like_type {
    ($ty:ident) => {
        impl FunctionLikeType for $ty {
            fn doc(&self) -> &Option<String> {
                &self.doc
            }
            fn doc_deprecated(&self) -> &Option<String> {
                &self.doc_deprecated
            }
            fn ret(&self) -> &Parameter {
                &self.ret
            }
            fn parameters(&self) -> &[Parameter] {
                &self.parameters
            }
            fn version(&self) -> &Option<Version> {
                &self.version
            }
            fn deprecated_version(&self) -> &Option<Version> {
                &self.deprecated_version
            }
        }
    };
}

impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Struct);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Signal, Fn, false);

impl_function_like_type!(Function);
impl_function_like_type!(Signal);

pub fn generate(env: &Env) {
    info!("Generating documentation {:?}", env.config.doc_target_path);
    save_to_file(&env.config.doc_target_path, env.config.make_backup, |w| {
        generate_doc(w, env)
    });
}

#[allow(clippy::type_complexity)]
fn generate_doc(w: &mut dyn Write, env: &Env) -> Result<()> {
    write_file_name(w, None)?;
    let mut generators: Vec<(&str, Box<dyn Fn(&mut dyn Write, &Env) -> Result<()>>)> = Vec::new();

    for info in env.analysis.objects.values() {
        if info.type_id.ns_id == MAIN && !env.is_totally_deprecated(info.deprecated_version) {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_object_doc(w, e, info)),
            ));
        }
    }

    for info in env.analysis.records.values() {
        if info.type_id.ns_id == MAIN && !env.is_totally_deprecated(info.deprecated_version) {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_record_doc(w, e, info)),
            ));
        }
    }

    for (tid, type_) in env.library.namespace_types(MAIN) {
        if let LType::Enumeration(enum_) = type_ {
            if !env
                .config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
                && !env.is_totally_deprecated(enum_.deprecated_version)
            {
                generators.push((
                    &enum_.name[..],
                    Box::new(move |w, e| create_enum_doc(w, e, enum_)),
                ));
            }
        } else if let LType::Bitfield(bitfield) = type_ {
            if !env
                .config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
                && !env.is_totally_deprecated(bitfield.deprecated_version)
            {
                generators.push((
                    &bitfield.name[..],
                    Box::new(move |w, e| create_bitfield_doc(w, e, bitfield)),
                ));
            }
        }
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);

    if let Some(ref global_functions) = env.analysis.global_functions {
        let functions = ns
            .functions
            .iter()
            .filter(|f| f.kind == library::FunctionKind::Global);

        for function in functions {
            if let Some(ref c_identifier) = function.c_identifier {
                let fn_new_name = (&global_functions.functions)
                    .iter()
                    .find(move |f| &f.glib_name == c_identifier)
                    .and_then(|analysed_f| analysed_f.new_name.clone());
                create_fn_doc(w, env, function, None, fn_new_name, HashSet::new())?;
            }
        }
    }

    let symbols = env.symbols.borrow();
    for constant in &ns.constants {
        // strings are mapped to a static
        let ty = if constant.c_type == "gchar*" {
            SType::Static
        } else {
            SType::Const
        };
        let ty_id = TypeStruct::new(ty, &constant.name);
        write_item_doc(w, &ty_id, |w| {
            if let Some(ref doc) = constant.doc {
                writeln!(w, "{}", reformat_doc(doc, &symbols, &constant.name))?;
            }
            Ok(())
        })?;
    }

{'fraction_non_alphanumeric': 0.13836833602584814, 'fraction_numerical': 0.0004846526655896607, 'mean_word_length': 1.961253288686917, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1035774', 'n_tokens_mistral': 3882, 'n_tokens_neox': 3847, 'n_words': 720}