code_blocks_server/
lib.rs

1pub mod types;
2use std::path::PathBuf;
3
4use anyhow::{Context, Result};
5use code_blocks::{Block, BlockTree};
6use tree_sitter::{Language, Parser, Query};
7use tree_sitter_installer::parser_installer::{self, InstallationStatus};
8
9pub use types::*;
10
11#[derive(Debug)]
12pub struct InstallLanguageArgs<F: FnMut(InstallationStatus)> {
13    pub download_cmd: String,
14    pub library_name: String,
15    pub install_dir: PathBuf,
16    pub report_progress: Option<F>,
17}
18
19pub type InstallLanguageResponse = PathBuf;
20
21pub fn install_language<F: FnMut(InstallationStatus)>(
22    args: InstallLanguageArgs<F>,
23) -> Result<InstallLanguageResponse> {
24    if !parser_installer::is_installed_at(&args.library_name, &args.install_dir) {
25        parser_installer::install_parser(
26            &args.download_cmd,
27            &args.library_name,
28            &args.install_dir,
29            args.report_progress,
30        )
31    } else {
32        Ok(parser_installer::get_compiled_lib_path(
33            &args.library_name,
34            &args.install_dir,
35        ))
36    }
37}
38
39#[derive(Debug)]
40pub struct GetSubtreesArgs {
41    pub queries: Vec<String>,
42    pub text: String,
43    pub language: Language,
44}
45
46pub type GetSubtreesResponse = Vec<BlockLocationTree>;
47
48pub fn get_subtrees(args: GetSubtreesArgs) -> Result<GetSubtreesResponse> {
49    let mut parser = Parser::new();
50    parser.set_language(args.language)?;
51
52    let text = args.text;
53    let tree = parser.parse(&text, None).context("Failed to parse text")?;
54
55    let mut queries = vec![];
56    for query in args.queries {
57        queries.push(Query::new(args.language, &query)?);
58    }
59
60    let items = code_blocks::get_query_subtrees(&queries, &tree, &text);
61
62    Ok(items.iter().map(Into::into).collect())
63}
64
65#[derive(Debug)]
66pub struct MoveBlockArgs<C: Fn(&Block, &Block) -> Result<()>> {
67    pub queries: Vec<String>,
68    pub text: String,
69    pub language: Language,
70    pub src_block: BlockLocation,
71    pub dst_block: BlockLocation,
72    pub assert_move_legal_fn: Option<C>,
73    pub force: bool,
74}
75
76#[derive(Debug)]
77pub struct MoveBlockResponse {
78    pub text: String,
79    pub new_src_start: usize,
80    pub new_dst_start: usize,
81}
82
83pub fn move_block<C: Fn(&Block, &Block) -> Result<()>>(
84    args: MoveBlockArgs<C>,
85) -> Result<MoveBlockResponse> {
86    fn copy_item_at<'tree>(
87        location: &BlockLocation,
88        trees: &[BlockTree<'tree>],
89    ) -> Option<Block<'tree>> {
90        for tree in trees {
91            if &BlockLocation::from(&tree.block) == location {
92                return Some(tree.block.clone());
93            }
94            if let Some(node) = copy_item_at(location, &tree.children) {
95                return Some(node);
96            }
97        }
98        None
99    }
100
101    let mut parser = Parser::new();
102    parser.set_language(args.language)?;
103
104    let tree = parser
105        .parse(&args.text, None)
106        .context("Failed to parse text")?;
107
108    let mut queries = vec![];
109    for query in args.queries {
110        queries.push(Query::new(args.language, &query)?);
111    }
112
113    let subtrees = code_blocks::get_query_subtrees(&queries, &tree, &args.text);
114
115    let src_block = copy_item_at(&args.src_block, &subtrees).context("Failed to find src item")?;
116    let dst_item = copy_item_at(&args.dst_block, &subtrees).context("Failed to find dst item")?;
117
118    let (text, new_src_start, new_dst_start) = code_blocks::move_block(
119        src_block,
120        dst_item,
121        &args.text,
122        args.assert_move_legal_fn,
123        args.force,
124    )?;
125
126    Ok(MoveBlockResponse {
127        text,
128        new_src_start,
129        new_dst_start,
130    })
131}