semantic_code_edit_mcp/languages/
json.rs

1use super::{LanguageCommon, LanguageName, traits::LanguageEditor};
2use anyhow::Result;
3use jsonformat::Indentation;
4use serde_json::Value;
5use std::collections::BTreeMap;
6use tree_sitter::Tree;
7
8pub fn language() -> Result<LanguageCommon> {
9    let language = tree_sitter_json::LANGUAGE.into();
10    let editor = Box::new(JsonEditor::new());
11    Ok(LanguageCommon {
12        name: LanguageName::Json,
13        file_extensions: &["json"],
14        language,
15        validation_query: None,
16        editor,
17    })
18}
19
20pub struct JsonEditor;
21
22impl Default for JsonEditor {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl JsonEditor {
29    pub fn new() -> Self {
30        Self
31    }
32}
33
34impl LanguageEditor for JsonEditor {
35    fn format_code(&self, source: &str) -> Result<String> {
36        let mut tab_count = 0;
37        let mut space_counts = BTreeMap::<usize, usize>::new();
38        let mut last_indentation = 0;
39        let mut last_change = 0;
40        for line in source.lines().take(100) {
41            if line.starts_with('\t') {
42                tab_count += 1;
43            } else {
44                let count = line.chars().take_while(|c| c == &' ').count();
45                let diff = count.abs_diff(last_indentation);
46                last_indentation = count;
47                if diff > 0 {
48                    last_change = diff;
49                }
50                let entry = space_counts.entry(last_change).or_default();
51                *entry += 1;
52            }
53        }
54
55        let custom;
56
57        let indentation_style = match space_counts
58            .into_iter()
59            .map(|(k, v)| (Some(k), v))
60            .chain(std::iter::once((None, tab_count)))
61            .max_by_key(|(_, count)| *count)
62        {
63            Some((Some(2), _)) => Indentation::TwoSpace,
64            Some((Some(4), _)) => Indentation::FourSpace,
65            Some((None, _)) => Indentation::Tab,
66            Some((Some(n), _)) => {
67                custom = " ".repeat(n);
68                Indentation::Custom(&custom)
69            }
70            None => Indentation::FourSpace,
71        };
72
73        Ok(jsonformat::format(source, indentation_style))
74    }
75
76    fn collect_errors(&self, _tree: &Tree, content: &str) -> Vec<usize> {
77        match serde_json::from_str::<Value>(content) {
78            Ok(_) => vec![],
79            Err(e) => {
80                vec![e.line().saturating_sub(1)]
81            }
82        }
83    }
84}