claudix 0.2.0

Local semantic search plugin for Claude Code
use tree_sitter::Node;

use crate::error::Result;
use crate::types::{Chunk, ChunkKind, FileHash, Language, RelativePath};

use super::chunk_with_grammar;

pub(super) fn chunk(path: &RelativePath, file_hash: FileHash, content: &str) -> Result<Vec<Chunk>> {
    chunk_with_grammar(
        tree_sitter_go::LANGUAGE.into(),
        "Go",
        path,
        Language::Go,
        file_hash,
        content,
        go_chunk_kind,
    )
}

fn go_chunk_kind(node: Node<'_>) -> Option<ChunkKind> {
    match node.kind() {
        "function_declaration" => Some(ChunkKind::Function),
        "method_declaration" => Some(ChunkKind::Method),
        "type_declaration" => {
            let has_struct = node.named_children(&mut node.walk()).any(|child| {
                child.kind() == "type_spec" && type_spec_contains(child, "struct_type")
            });
            let has_interface = node.named_children(&mut node.walk()).any(|child| {
                child.kind() == "type_spec" && type_spec_contains(child, "interface_type")
            });

            if has_struct {
                Some(ChunkKind::Struct)
            } else if has_interface {
                Some(ChunkKind::Interface)
            } else {
                None
            }
        }
        _ => None,
    }
}

fn type_spec_contains(type_spec: Node<'_>, target_kind: &str) -> bool {
    type_spec
        .named_children(&mut type_spec.walk())
        .any(|child| child.kind() == target_kind)
}