diff --git a/Cargo.lock b/Cargo.lock index d4bded0..3b80a40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,6 +488,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "toml", "tower-lsp", ] diff --git a/crates/analyzer/Cargo.toml b/crates/analyzer/Cargo.toml index 0b830f2..e418cb5 100644 --- a/crates/analyzer/Cargo.toml +++ b/crates/analyzer/Cargo.toml @@ -22,3 +22,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" ropey = "1" heck = "0.5.0" +toml = "1.1.2" diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index c7d2d53..3ce6236 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -7,10 +7,11 @@ use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use heck::ToSnakeCase; +use mist_parser::MistFmtConfig; use mist_parser::error::ParseError; use mist_parser::rev_mapper::{Mapping, MistMap, RustMap}; use ropey::Rope; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use tokio::sync::Mutex; use tower_lsp::lsp_types::{self, *}; @@ -1357,8 +1358,18 @@ impl LanguageServer for Backend { .get(&mist_path) .map_or_else(|| Err(tower_lsp::jsonrpc::Error::internal_error()), Ok)?; - let new_text = format_mist(&old_text.to_string()) - .map_err(|_| tower_lsp::jsonrpc::Error::internal_error())?; + let ws = match &*self.workspace_folder.lock().await { + Some(p) => p.clone(), + None => return Ok(None), + }; + + let new_text = format_mist( + &old_text.to_string(), + read_mist_fmt(&ws).unwrap_or_else(|| MistFmtConfig { + allman_bracket_style: true, + }), + ) + .map_err(|_| tower_lsp::jsonrpc::Error::internal_error())?; Ok(Some(vec![TextEdit { new_text, @@ -1820,24 +1831,38 @@ fn read_mist_package(workspace_root: &Path) -> String { let toml_path = workspace_root.join("Mist.toml"); let content = match std::fs::read_to_string(&toml_path) { Ok(c) => c, - Err(_) => return "main.mist".to_string(), - }; - for line in content.lines() { - let line = line.trim(); - if let Some(rest) = line.strip_prefix("package") { - if let Some(eq_pos) = rest.find('=') { - let val = rest[eq_pos + 1..] - .trim() - .trim_matches('"') - .trim() - .to_string(); - if !val.is_empty() { - return val; - } - } + Err(_) => { + return "main.mist".to_string(); } - } - "main.mist".to_string() + }; + + toml::from_str::(&content) + .ok() + .and_then(|v| v.package.to_str().map(String::from)) + .unwrap_or_else(|| "main.mist".to_string()) +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct MistConfig { + pub package: PathBuf, + pub packages: Vec, + pub fmt: Option, +} + +fn read_mist_fmt(workspace_root: &Path) -> Option { + let toml_path = workspace_root.join("Mist.toml"); + let content = match std::fs::read_to_string(&toml_path) { + Ok(c) => c, + Err(_) => { + return Some(MistFmtConfig { + allman_bracket_style: true, + }); + } + }; + + toml::from_str::(&content) + .ok() + .and_then(|v| v.fmt) } fn compute_mod_decls( diff --git a/crates/analyzer/src/transpiler.rs b/crates/analyzer/src/transpiler.rs index 8413a8e..7379da6 100644 --- a/crates/analyzer/src/transpiler.rs +++ b/crates/analyzer/src/transpiler.rs @@ -1,9 +1,9 @@ use std::path::{Path, PathBuf}; -use mist_codegen::fmt::MistCodegen; use mist_codegen::RustCodegen; -use mist_parser::parse; +use mist_codegen::fmt::MistCodegen; use mist_parser::rev_mapper::Mapping; +use mist_parser::{MistFmtConfig, parse}; pub struct TranspiledFile { pub mist_path: PathBuf, @@ -85,10 +85,10 @@ pub fn transpile_mist_no_sem( }) } -pub fn format_mist(source: &str) -> Result { +pub fn format_mist(source: &str, config: MistFmtConfig) -> Result { let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; - let mut codegen = MistCodegen::new(); + let mut codegen = MistCodegen::new(config); codegen.generate(parsed.mod_attributes); let output = codegen.generate(parsed.items); diff --git a/crates/codegen/src/fmt/mod.rs b/crates/codegen/src/fmt/mod.rs index b714300..916ebe2 100644 --- a/crates/codegen/src/fmt/mod.rs +++ b/crates/codegen/src/fmt/mod.rs @@ -2,21 +2,23 @@ pub mod expr; pub mod statement; pub mod top_level; -use mist_parser::ast::*; +use mist_parser::{MistFmtConfig, ast::*}; pub struct Context { pub expr_ensure_semicolon: bool, } pub struct MistCodegen { + config: MistFmtConfig, indent_amount: u8, output: String, indent: usize, } impl MistCodegen { - pub fn new() -> Self { + pub fn new(config: MistFmtConfig) -> Self { Self { + config, output: String::new(), indent: 0, indent_amount: 4, @@ -46,9 +48,22 @@ impl MistCodegen { self.add(&line); } + pub fn start_indent(&mut self) { + if self.config.allman_bracket_style { + self.addln(""); + self.add_indented(""); + } else { + self.add(" "); + } + } + pub fn start_bracket(&mut self) { - self.addln(""); - self.add_indentedln("{"); + if self.config.allman_bracket_style { + self.addln(""); + self.add_indentedln("{"); + } else { + self.addln(" {"); + } self.indent += 1; } diff --git a/crates/codegen/src/fmt/top_level.rs b/crates/codegen/src/fmt/top_level.rs index 60923e0..13439ab 100644 --- a/crates/codegen/src/fmt/top_level.rs +++ b/crates/codegen/src/fmt/top_level.rs @@ -78,8 +78,7 @@ impl GenMist for FunctionDecl { } if let Some(body) = &self.body { - cg.addln(""); - cg.add_indented(""); + cg.start_indent(); body.gen_mist(ctx, cg); cg.addln(""); } else { @@ -308,8 +307,8 @@ impl GenMist for TopLevelKind { } param.gen_mist(ctx, cg); } - cg.addln(") "); - cg.add_indented(""); + cg.add(") "); + cg.start_indent(); constructor.item.body.gen_mist(ctx, cg); cg.addln(""); diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 910a175..aa08f60 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -20,6 +20,11 @@ pub struct Program { pub items: Vec, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct MistFmtConfig { + pub allman_bracket_style: bool, +} + pub fn parse<'a>(source: &'a str) -> Result> { let mut pairs = MistParser::parse(Rule::program, source)?;