rrubocop 0.8.15

10x faster RuboCop drop-in. Same output format and configs, without maintaining RuboCop gems.
//! Layout/SpaceInsideReferenceBrackets.

use tree_sitter::Node;

use crate::cop::layout::space_delim::{self, DelimSpace};
use crate::cop::{Cop, CopConfig};
use crate::correction::Correction;
use crate::diagnostic::Diagnostic;
use crate::parse::source::SourceFile;

pub struct SpaceInsideReferenceBrackets;

fn find_brackets<'a>(node: Node<'a>) -> Option<(Node<'a>, Node<'a>)> {
    let mut cur = node.walk();
    let kids: Vec<_> = node.children(&mut cur).collect();
    let lb = kids.iter().find(|c| c.kind() == "[").copied()?;
    let rb = kids.iter().rev().find(|c| c.kind() == "]").copied()?;
    Some((lb, rb))
}

fn check_empty(
    cop: &dyn Cop,
    source: &SourceFile,
    config: &CopConfig,
    lb: Node<'_>,
    d: &DelimSpace,
    diagnostics: &mut Vec<Diagnostic>,
    corrections: &mut Option<&mut Vec<Correction>>,
) {
    let want_e = config.get_str("EnforcedStyleForEmptyBrackets", "no_space") == "space";
    let has = d.inner_e > d.inner_s;
    if want_e == has {
        return;
    }
    let cmd = if want_e { "Use" } else { "Do not use" };
    space_delim::report_at(
        cop,
        source,
        lb.start_byte(),
        format!("{cmd} space inside empty reference brackets."),
        diagnostics,
        corrections,
        d.inner_s,
        d.inner_e,
        if want_e { " ".into() } else { String::new() },
        None,
    );
}

impl Cop for SpaceInsideReferenceBrackets {
    fn name(&self) -> &'static str {
        "Layout/SpaceInsideReferenceBrackets"
    }
    fn supports_autocorrect(&self) -> bool {
        true
    }
    fn interested_node_kinds(&self) -> &'static [&'static str] {
        &["element_reference"]
    }

    fn check_node(
        &self,
        source: &SourceFile,
        node: Node<'_>,
        config: &CopConfig,
        diagnostics: &mut Vec<Diagnostic>,
        mut corrections: Option<&mut Vec<Correction>>,
    ) {
        let style = config.get_str("EnforcedStyle", "no_space");
        let bytes = source.as_bytes();
        let Some((lb, rb)) = find_brackets(node) else {
            return;
        };
        let Some(d) = space_delim::scan_inner(bytes, lb.end_byte(), rb.start_byte()) else {
            return;
        };
        if space_delim::is_blank_inner(bytes, d.inner_s, d.inner_e) {
            check_empty(self, source, config, lb, &d, diagnostics, &mut corrections);
            return;
        }
        let want = style == "space";
        let cmd = if want { "Use" } else { "Do not use" };
        let msg = format!("{cmd} space inside reference brackets.");
        space_delim::enforce_spaces(
            self,
            source,
            bytes,
            &d,
            want,
            lb.start_byte(),
            d.inner_e.saturating_sub(1),
            &msg,
            diagnostics,
            &mut corrections,
        );
    }
}