codeinput 0.1.0

A powerful library for parsing, analyzing, and managing CODEOWNERS files. Provides advanced querying capabilities, ownership analysis, and tag-based file organization.
Documentation
use tower_lsp::jsonrpc::Result as LspResult;
use url::Url;

use crate::core::types::{CodeownersCache, OwnerType};

use super::server::LspServer;
use super::types::*;

impl LspServer {
    pub async fn get_file_ownership_command(&self, uri_str: String) -> LspResult<Option<FileOwnershipInfo>> {
        let Ok(uri) = Url::parse(&uri_str) else {
            return Err(tower_lsp::jsonrpc::Error::invalid_params("Invalid URI"));
        };
        Ok(self.get_file_ownership(&uri).await)
    }

    pub async fn list_files(&self, workspace_uri: Option<Url>) -> LspResult<ListFilesResponse> {
        let workspaces = self.workspaces.read().await;

        let files = if let Some(uri) = workspace_uri {
            if let Some(state) = workspaces.get(&uri) {
                Self::collect_files_from_cache(&state.cache)
            } else {
                Vec::new()
            }
        } else {
            let mut all_files = Vec::new();
            for state in workspaces.values() {
                all_files.extend(Self::collect_files_from_cache(&state.cache));
            }
            all_files
        };

        Ok(ListFilesResponse { files })
    }

    pub async fn list_owners(&self, workspace_uri: Option<Url>) -> LspResult<ListOwnersResponse> {
        let workspaces = self.workspaces.read().await;

        let owners = if let Some(uri) = workspace_uri {
            if let Some(state) = workspaces.get(&uri) {
                Self::collect_owners_from_cache(&state.cache)
            } else {
                Vec::new()
            }
        } else {
            let mut all_owners = Vec::new();
            for state in workspaces.values() {
                all_owners.extend(Self::collect_owners_from_cache(&state.cache));
            }
            all_owners
        };

        Ok(ListOwnersResponse { owners })
    }

    pub async fn list_tags(&self, workspace_uri: Option<Url>) -> LspResult<ListTagsResponse> {
        let workspaces = self.workspaces.read().await;

        let tags = if let Some(uri) = workspace_uri {
            if let Some(state) = workspaces.get(&uri) {
                Self::collect_tags_from_cache(&state.cache)
            } else {
                Vec::new()
            }
        } else {
            let mut all_tags = Vec::new();
            for state in workspaces.values() {
                all_tags.extend(Self::collect_tags_from_cache(&state.cache));
            }
            all_tags
        };

        Ok(ListTagsResponse { tags })
    }

    fn collect_files_from_cache(cache: &CodeownersCache) -> Vec<FileOwnershipInfo> {
        cache
            .files
            .iter()
            .map(|entry| FileOwnershipInfo {
                path: entry.path.clone(),
                owners: entry.owners.clone(),
                tags: entry.tags.clone(),
                is_unowned: entry.owners.is_empty()
                    || entry
                        .owners
                        .iter()
                        .any(|o| matches!(o.owner_type, OwnerType::Unowned)),
            })
            .collect()
    }

    fn collect_owners_from_cache(cache: &CodeownersCache) -> Vec<OwnerInfo> {
        cache
            .owners_map
            .iter()
            .map(|(owner, files)| OwnerInfo {
                owner: owner.clone(),
                files: files.clone(),
            })
            .collect()
    }

    fn collect_tags_from_cache(cache: &CodeownersCache) -> Vec<TagInfo> {
        cache
            .tags_map
            .iter()
            .map(|(tag, files)| TagInfo {
                tag: tag.clone(),
                files: files.clone(),
            })
            .collect()
    }
}