semantic_code_edit_mcp/languages/
json.rs1use 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}