diff --git a/README.md b/README.md index 4c64a36c..abddcb67 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ mdsf init | Dart | `dart_format` | | Elixir | `mix_format` | | Elm | `elm-format` | +| Erlang | `erlfmt` | | Gleam | `gleam_format` | | Go | `gofmt`, `gofumpt`, `goimports` | | GraphQL | `prettier` | @@ -94,7 +95,7 @@ mdsf init | Python | `autopep8`, `black`, `blue`, `isort`, `ruff`, `usort`, `yapf` | | ReScript | `rescript_format` | | Roc | `roc_format` | -| Ruby | `rubocop`, `rubyfmt`, `rufo` | +| Ruby | `rubocop`, `rubyfmt`, `rufo`, `standardrb` | | Rust | `rustfmt` | | Scala | `scalafmt` | | Shell | `beautysh`, `shfmt` | diff --git a/schemas/v0.0.2/mdsf.schema.json b/schemas/v0.0.2/mdsf.schema.json index 43ffb4c5..599cb50c 100644 --- a/schemas/v0.0.2/mdsf.schema.json +++ b/schemas/v0.0.2/mdsf.schema.json @@ -113,6 +113,17 @@ } ] }, + "erlang": { + "default": { + "enabled": true, + "formatter": "erlfmt" + }, + "allOf": [ + { + "$ref": "#/definitions/Lang_for_Erlang" + } + ] + }, "gleam": { "default": { "enabled": true, @@ -361,7 +372,7 @@ "ruby": { "default": { "enabled": true, - "formatter": [["rubocop", "rufo", "rubyfmt"]] + "formatter": [["rubocop", "rufo", "rubyfmt", "standardrb"]] }, "allOf": [ { @@ -532,6 +543,10 @@ "type": "string", "enum": ["elm-format"] }, + "Erlang": { + "type": "string", + "enum": ["erlfmt"] + }, "Gleam": { "type": "string", "enum": ["gleam_format"] @@ -696,6 +711,18 @@ } } }, + "Lang_for_Erlang": { + "type": "object", + "required": ["enabled", "formatter"], + "properties": { + "enabled": { + "type": "boolean" + }, + "formatter": { + "$ref": "#/definitions/MdsfFormatter_for_Erlang" + } + } + }, "Lang_for_Gleam": { "type": "object", "required": ["enabled", "formatter"], @@ -1242,6 +1269,19 @@ } ] }, + "MdsfFormatter_for_Erlang": { + "anyOf": [ + { + "$ref": "#/definitions/Erlang" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/MdsfFormatter_for_Erlang" + } + } + ] + }, "MdsfFormatter_for_Gleam": { "anyOf": [ { @@ -1722,7 +1762,7 @@ }, "Ruby": { "type": "string", - "enum": ["rubyfmt", "rubocop", "rufo"] + "enum": ["rubyfmt", "rubocop", "rufo", "standardrb"] }, "Rust": { "type": "string", diff --git a/src/config.rs b/src/config.rs index fd66f546..b66dfc79 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,12 +2,13 @@ use schemars::JsonSchema; use crate::languages::{ blade::Blade, c::C, clojure::Clojure, cpp::Cpp, crystal::Crystal, csharp::CSharp, css::Css, - dart::Dart, elixir::Elixir, elm::Elm, gleam::Gleam, go::Go, graphql::GraphQL, groovy::Groovy, - haskell::Haskell, html::Html, java::Java, javascript::JavaScript, json::Json, just::Just, - kotlin::Kotlin, lua::Lua, markdown::Markdown, nim::Nim, objective_c::ObjectiveC, ocaml::OCaml, - perl::Perl, protobuf::Protobuf, purescript::PureScript, python::Python, rescript::ReScript, - roc::Roc, ruby::Ruby, rust::Rust, scala::Scala, shell::Shell, sql::Sql, swift::Swift, - toml::Toml, typescript::TypeScript, vue::Vue, xml::Xml, yaml::Yaml, zig::Zig, Lang, + dart::Dart, elixir::Elixir, elm::Elm, erlang::Erlang, gleam::Gleam, go::Go, graphql::GraphQL, + groovy::Groovy, haskell::Haskell, html::Html, java::Java, javascript::JavaScript, json::Json, + just::Just, kotlin::Kotlin, lua::Lua, markdown::Markdown, nim::Nim, objective_c::ObjectiveC, + ocaml::OCaml, perl::Perl, protobuf::Protobuf, purescript::PureScript, python::Python, + rescript::ReScript, roc::Roc, ruby::Ruby, rust::Rust, scala::Scala, shell::Shell, sql::Sql, + swift::Swift, toml::Toml, typescript::TypeScript, vue::Vue, xml::Xml, yaml::Yaml, zig::Zig, + Lang, }; #[derive(Debug, serde::Serialize, serde::Deserialize, JsonSchema)] @@ -47,6 +48,9 @@ pub struct MdsfConfig { #[serde(default)] pub elm: Lang, + #[serde(default)] + pub erlang: Lang, + #[serde(default)] pub gleam: Lang, @@ -165,6 +169,7 @@ impl Default for MdsfConfig { dart: Lang::::default(), elixir: Lang::::default(), elm: Lang::::default(), + erlang: Lang::::default(), gleam: Lang::::default(), go: Lang::::default(), graphql: Lang::::default(), diff --git a/src/formatters/erlfmt.rs b/src/formatters/erlfmt.rs new file mode 100644 index 00000000..8c4a1c8c --- /dev/null +++ b/src/formatters/erlfmt.rs @@ -0,0 +1,42 @@ +use super::execute_command; + +#[inline] +pub fn format_using_erlfmt(file_path: &std::path::Path) -> std::io::Result<(bool, Option)> { + let mut cmd = std::process::Command::new("erlfmt"); + + cmd.arg("-w") + .arg(format!("'{}'", file_path.to_string_lossy())); + + execute_command(&mut cmd, file_path) +} + +#[cfg(test)] +mod test_erlfmt { + use crate::{ + formatters::{erlfmt::format_using_erlfmt, setup_snippet}, + languages::Language, + }; + + #[test_with::executable(erlfmt)] + #[test] + fn it_should_format_erlang() { + let input = "what_is(Erlang) -> +case Erlang of movie->[hello(mike,joe,robert),credits]; language->formatting_arguments end +."; + + let expected_output = "what_is(Erlang) -> + case Erlang of + movie -> [hello(mike, joe, robert), credits]; + language -> no_more_formatting_arguments + end."; + let snippet = setup_snippet(input, Language::Erlang.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_erlfmt(snippet.path()) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } +} diff --git a/src/formatters/mod.rs b/src/formatters/mod.rs index 78006c34..b8e0a1f4 100644 --- a/src/formatters/mod.rs +++ b/src/formatters/mod.rs @@ -17,6 +17,7 @@ pub mod crystal_format; pub mod dart_format; pub mod deno_fmt; pub mod elm_format; +pub mod erlfmt; pub mod fourmolu; pub mod gleam_format; pub mod gofmt; @@ -136,6 +137,7 @@ pub fn format_snippet(config: &MdsfConfig, language: &Language, code: &str) -> S Language::Dart => config.dart.format(snippet_path), Language::Elixir => config.elixir.format(snippet_path), Language::Elm => config.elm.format(snippet_path), + Language::Erlang => config.erlang.format(snippet_path), Language::Gleam => config.gleam.format(snippet_path), Language::Go => config.go.format(snippet_path), Language::GraphQL => config.graphql.format(snippet_path), diff --git a/src/languages/erlang.rs b/src/languages/erlang.rs new file mode 100644 index 00000000..c4bc429c --- /dev/null +++ b/src/languages/erlang.rs @@ -0,0 +1,102 @@ +use schemars::JsonSchema; + +use crate::formatters::{erlfmt::format_using_erlfmt, MdsfFormatter}; + +use super::{Lang, LanguageFormatter}; + +#[derive(Debug, Default, serde::Serialize, serde::Deserialize, JsonSchema)] +#[cfg_attr(test, derive(PartialEq, Eq))] +pub enum Erlang { + #[default] + #[serde(rename = "erlfmt")] + Erlfmt, +} + +impl Default for Lang { + #[inline] + fn default() -> Self { + Self { + enabled: true, + formatter: MdsfFormatter::::default(), + } + } +} + +impl Default for MdsfFormatter { + #[inline] + fn default() -> Self { + Self::Single(Erlang::Erlfmt) + } +} + +impl LanguageFormatter for Erlang { + #[inline] + fn format_snippet( + &self, + snippet_path: &std::path::Path, + ) -> std::io::Result<(bool, Option)> { + match self { + Self::Erlfmt => format_using_erlfmt(snippet_path), + } + } +} + +#[cfg(test)] +mod test_erlang { + use crate::{ + formatters::{setup_snippet, MdsfFormatter}, + languages::Lang, + }; + + use super::Erlang; + + const INPUT: &str = "what_is(Erlang) -> +case Erlang of movie->[hello(mike,joe,robert),credits]; language->formatting_arguments end +."; + + const EXTENSION: &str = crate::languages::Language::Gleam.to_file_ext(); + + #[test] + fn it_should_be_enabled_by_default() { + assert!(Lang::::default().enabled); + } + + #[test] + fn it_should_not_format_when_enabled_is_false() { + let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + assert!(Lang:: { + enabled: false, + formatter: MdsfFormatter::Single(Erlang::default()) + } + .format(snippet_path) + .expect("it to not fail") + .is_none()); + } + + #[test_with::executable(erlfmt)] + #[test] + fn test_erlfmt() { + let l = Lang:: { + enabled: true, + formatter: MdsfFormatter::Single(Erlang::Erlfmt), + }; + + let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + let output = l + .format(snippet_path) + .expect("it to not fail") + .expect("it to be a snippet"); + + let expected_output = "what_is(Erlang) -> + case Erlang of + movie -> [hello(mike, joe, robert), credits]; + language -> no_more_formatting_arguments + end."; + + assert_eq!(output, expected_output); + } +} diff --git a/src/languages/mod.rs b/src/languages/mod.rs index 4baf6388..b2a0cc72 100644 --- a/src/languages/mod.rs +++ b/src/languages/mod.rs @@ -13,6 +13,7 @@ pub enum Language { Dart, Elixir, Elm, + Erlang, Gleam, Go, GraphQL, @@ -54,7 +55,6 @@ pub enum Language { // TODO: Dockerfile, // TODO: XML, // TODO: D, - // TODO: Erlang, // TODO: R, } @@ -68,6 +68,7 @@ pub mod css; pub mod dart; pub mod elixir; pub mod elm; +pub mod erlang; pub mod gleam; pub mod go; pub mod graphql; @@ -123,6 +124,7 @@ impl Language { "dart" => Some(Self::Dart), "elixir" => Some(Self::Elixir), "elm" => Some(Self::Elm), + "erlang" => Some(Self::Erlang), "gleam" => Some(Self::Gleam), "go" | "golang" => Some(Self::Go), "graphql" | "gql" => Some(Self::GraphQL), @@ -176,6 +178,7 @@ impl Language { Self::Dart => ".dart", Self::Elixir => ".ex", Self::Elm => ".elm", + Self::Erlang => ".erl", Self::Gleam => ".gleam", Self::Go => ".go", Self::GraphQL => ".gql",