code-blocks-server 0.6.0

A tool to re-order your code
Documentation
pub mod types;
use std::path::PathBuf;

use anyhow::{Context, Result};
use code_blocks::{Block, BlockTree};
use tree_sitter::{Language, Parser, Query};
use tree_sitter_installer::parser_installer::{self, InstallationStatus};

pub use types::*;

#[derive(Debug)]
pub struct InstallLanguageArgs<F: FnMut(InstallationStatus)> {
    pub download_cmd: String,
    pub library_name: String,
    pub install_dir: PathBuf,
    pub report_progress: Option<F>,
}

pub type InstallLanguageResponse = PathBuf;

pub fn install_language<F: FnMut(InstallationStatus)>(
    args: InstallLanguageArgs<F>,
) -> Result<InstallLanguageResponse> {
    if !parser_installer::is_installed_at(&args.library_name, &args.install_dir) {
        parser_installer::install_parser(
            &args.download_cmd,
            &args.library_name,
            &args.install_dir,
            args.report_progress,
        )
    } else {
        Ok(parser_installer::get_compiled_lib_path(
            &args.library_name,
            &args.install_dir,
        ))
    }
}

#[derive(Debug)]
pub struct GetSubtreesArgs {
    pub queries: Vec<String>,
    pub text: String,
    pub language: Language,
}

pub type GetSubtreesResponse = Vec<BlockLocationTree>;

pub fn get_subtrees(args: GetSubtreesArgs) -> Result<GetSubtreesResponse> {
    let mut parser = Parser::new();
    parser.set_language(args.language)?;

    let text = args.text;
    let tree = parser.parse(&text, None).context("Failed to parse text")?;

    let mut queries = vec![];
    for query in args.queries {
        queries.push(Query::new(args.language, &query)?);
    }

    let items = code_blocks::get_query_subtrees(&queries, &tree, &text);

    Ok(items.iter().map(Into::into).collect())
}

#[derive(Debug)]
pub struct MoveBlockArgs<C: Fn(&Block, &Block) -> Result<()>> {
    pub queries: Vec<String>,
    pub text: String,
    pub language: Language,
    pub src_block: BlockLocation,
    pub dst_block: BlockLocation,
    pub assert_move_legal_fn: Option<C>,
    pub force: bool,
}

#[derive(Debug)]
pub struct MoveBlockResponse {
    pub text: String,
    pub new_src_start: usize,
    pub new_dst_start: usize,
}

pub fn move_block<C: Fn(&Block, &Block) -> Result<()>>(
    args: MoveBlockArgs<C>,
) -> Result<MoveBlockResponse> {
    fn copy_item_at<'tree>(
        location: &BlockLocation,
        trees: &[BlockTree<'tree>],
    ) -> Option<Block<'tree>> {
        for tree in trees {
            if &BlockLocation::from(&tree.block) == location {
                return Some(tree.block.clone());
            }
            if let Some(node) = copy_item_at(location, &tree.children) {
                return Some(node);
            }
        }
        None
    }

    let mut parser = Parser::new();
    parser.set_language(args.language)?;

    let tree = parser
        .parse(&args.text, None)
        .context("Failed to parse text")?;

    let mut queries = vec![];
    for query in args.queries {
        queries.push(Query::new(args.language, &query)?);
    }

    let subtrees = code_blocks::get_query_subtrees(&queries, &tree, &args.text);

    let src_block = copy_item_at(&args.src_block, &subtrees).context("Failed to find src item")?;
    let dst_item = copy_item_at(&args.dst_block, &subtrees).context("Failed to find dst item")?;

    let (text, new_src_start, new_dst_start) = code_blocks::move_block(
        src_block,
        dst_item,
        &args.text,
        args.assert_move_legal_fn,
        args.force,
    )?;

    Ok(MoveBlockResponse {
        text,
        new_src_start,
        new_dst_start,
    })
}