diff --git a/Cargo.lock b/Cargo.lock index 0cd9ee4412..8f9eae1591 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,19 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -141,6 +154,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.5.2" @@ -201,6 +220,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + [[package]] name = "binstall-tar" version = "0.4.42" @@ -590,6 +615,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + [[package]] name = "cpufeatures" version = "0.2.16" @@ -718,7 +749,7 @@ checksum = "eaa2c11e844048ceff84f99d2c85ebe2fd025fb89f21cf5378431c8e7458d71a" dependencies = [ "console", "fuzzy-matcher", - "itertools", + "itertools 0.13.0", "once_cell", "termcolor", ] @@ -1241,6 +1272,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.2" @@ -1684,6 +1721,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -1877,6 +1923,29 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "logos" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +dependencies = [ + "beef", + "fnv", + "proc-macro2", + "quote", + "regex-syntax 0.6.29", + "syn 1.0.109", +] + [[package]] name = "lua-src" version = "547.0.0" @@ -2057,7 +2126,7 @@ dependencies = [ "indicatif", "indoc", "insta", - "itertools", + "itertools 0.13.0", "junction", "log", "md-5", @@ -2091,6 +2160,7 @@ dependencies = [ "strum", "sys-info", "tabled", + "taplo", "tar", "tempfile", "tera", @@ -2126,7 +2196,7 @@ dependencies = [ "mlua_derive", "num-traits", "parking_lot", - "rustc-hash", + "rustc-hash 2.1.0", "serde", "serde-value", ] @@ -2150,7 +2220,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "870d71c172fcf491c6b5fb4c04160619a2ee3e5a42a1402269c66bcbf1dd4deb" dependencies = [ - "itertools", + "itertools 0.13.0", "once_cell", "proc-macro-error2", "proc-macro2", @@ -2641,7 +2711,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.0", "rustls", "socket2", "thiserror 2.0.6", @@ -2659,7 +2729,7 @@ dependencies = [ "getrandom", "rand", "ring", - "rustc-hash", + "rustc-hash 2.1.0", "rustls", "rustls-pki-types", "slab", @@ -2890,12 +2960,30 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" +[[package]] +name = "rowan" +version = "0.15.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d" +dependencies = [ + "countme", + "hashbrown 0.14.5", + "rustc-hash 1.1.0", + "text-size", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.0" @@ -3495,6 +3583,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "taplo" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010941ac4171eaf12f1e26dfc11dadaf78619ea2330940fef01fe6bb0442d14d" +dependencies = [ + "ahash", + "arc-swap", + "either", + "globset", + "itertools 0.10.5", + "logos", + "once_cell", + "rowan", + "serde", + "serde_json", + "thiserror 1.0.69", + "time", + "tracing", +] + [[package]] name = "tar" version = "0.4.43" @@ -3582,6 +3691,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + [[package]] name = "thiserror" version = "1.0.69" @@ -3639,6 +3754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", @@ -3796,9 +3912,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -3876,7 +4004,7 @@ dependencies = [ "bzip2", "document-features", "flate2", - "itertools", + "itertools 0.13.0", "lazy-regex", "log", "platforms", @@ -4011,7 +4139,7 @@ dependencies = [ "clap", "heck 0.5.0", "indexmap 2.7.0", - "itertools", + "itertools 0.13.0", "kdl", "log", "miette", @@ -4068,7 +4196,7 @@ version = "6.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25d498b63d1fdb376b4250f39ab3a5ee8d103957346abacd911e2d8b612c139" dependencies = [ - "itertools", + "itertools 0.13.0", "nom", "serde", ] @@ -4081,7 +4209,7 @@ checksum = "d4c44e4ec114bba1eeed55bc3a47ced72545cd2ffa04ce0ec0bdba1fb535807d" dependencies = [ "homedir", "indexmap 2.7.0", - "itertools", + "itertools 0.13.0", "log", "mlua", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 72e60e0d78..4f1814e4e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,6 +110,7 @@ siphasher = "1" strum = { version = "0.26", features = ["derive"] } sys-info = "0.9" tabled = { version = "0.17", features = ["ansi"] } +taplo = "0.13" tar = "0.4" tempfile = "3" tera = "1" diff --git a/docs/.vitepress/cli_commands.ts b/docs/.vitepress/cli_commands.ts index c4823475c3..664ee868c3 100644 --- a/docs/.vitepress/cli_commands.ts +++ b/docs/.vitepress/cli_commands.ts @@ -105,6 +105,9 @@ export const commands: { [key: string]: Command } = { exec: { hide: false, }, + format: { + hide: false, + }, generate: { hide: false, subcommands: { diff --git a/docs/cli/format.md b/docs/cli/format.md new file mode 100644 index 0000000000..7ed34c1656 --- /dev/null +++ b/docs/cli/format.md @@ -0,0 +1,17 @@ +# `mise format` + +- **Usage**: `mise format [-a --all]` +- **Aliases**: `fmt` +- **Source code**: [`src/cli/format.rs`](https://github.com/jdx/mise/blob/main/src/cli/format.rs) + +Formats mise.toml + +## Flags + +### `-a --all` + +Format all files from the current directory + +Examples: + + mise format diff --git a/docs/cli/index.md b/docs/cli/index.md index f91c7b84ed..478d353318 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -69,6 +69,7 @@ Answer yes to all confirmation prompts - [`mise en [-s --shell ] [DIR]`](/cli/en.md) - [`mise env [FLAGS] [TOOL@VERSION]...`](/cli/env.md) - [`mise exec [FLAGS] [TOOL@VERSION]... [COMMAND]...`](/cli/exec.md) +- [`mise format [-a --all]`](/cli/format.md) - [`mise generate `](/cli/generate.md) - [`mise generate git-pre-commit [FLAGS]`](/cli/generate/git-pre-commit.md) - [`mise generate github-action [FLAGS]`](/cli/generate/github-action.md) diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 6fd7834e78..778cfeb1fe 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -89,6 +89,9 @@ Exports env vars to activate mise a single time mise\-exec(1) Execute a command with tool(s) set .TP +mise\-format(1) +Formats mise.toml +.TP mise\-generate(1) [experimental] Generate files for various tools/services .TP diff --git a/mise.usage.kdl b/mise.usage.kdl index 8eb87a5313..7e69f58442 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -424,6 +424,14 @@ The "--" separates runtimes from the commands to pass along to the subprocess."# arg "[TOOL@VERSION]..." help="Tool(s) to start e.g.: node@20 python@3.10" var=true arg "[COMMAND]..." help="Command string to execute (same as --command)" var=true } +cmd "format" help="Formats mise.toml" { + alias "fmt" + after_long_help r"Examples: + + $ mise format +" + flag "-a --all" help="Format all files from the current directory" +} cmd "generate" subcommand_required=true help="[experimental] Generate files for various tools/services" { alias "gen" alias "g" hide=true diff --git a/src/cli/format.rs b/src/cli/format.rs new file mode 100644 index 0000000000..6bfb5d424a --- /dev/null +++ b/src/cli/format.rs @@ -0,0 +1,67 @@ +use crate::config::ALL_TOML_CONFIG_FILES; +use crate::{config, dirs, file}; +use eyre::bail; +use taplo::formatter::Options; + +/// Formats mise.toml +#[derive(Debug, clap::Args)] +#[clap(visible_alias="fmt", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Format { + /// Format all files from the current directory + #[clap(short, long)] + pub all: bool, +} + +impl Format { + pub fn run(self) -> eyre::Result<()> { + let cwd = dirs::CWD.clone().unwrap_or_default(); + let configs = if self.all { + ALL_TOML_CONFIG_FILES.clone() + } else { + config::config_files_in_dir(&cwd) + }; + if configs.is_empty() { + bail!("No config file found in current directory"); + } + for p in configs { + if !p.ends_with("toml") { + continue; + } + let toml = file::read_to_string(&p)?; + let toml = taplo::formatter::format( + &toml, + Options { + align_entries: false, + align_comments: true, + align_single_comments: true, + array_trailing_comma: true, + array_auto_expand: true, + inline_table_expand: true, + array_auto_collapse: true, + compact_arrays: true, + compact_inline_tables: false, + compact_entries: false, + column_width: 80, + indent_tables: false, + indent_entries: false, + indent_string: " ".to_string(), + trailing_newline: true, + reorder_keys: false, + reorder_arrays: false, + allowed_blank_lines: 2, + crlf: false, + }, + ); + file::write(&p, &toml)?; + } + + Ok(()) + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + + $ mise format +"# +); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index cc5a1f248b..396ed10902 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -24,6 +24,7 @@ mod en; mod env; pub mod exec; mod external; +mod format; mod generate; mod global; mod hook_env; @@ -167,6 +168,7 @@ pub enum Commands { En(en::En), Env(env::Env), Exec(exec::Exec), + Format(format::Format), Generate(generate::Generate), Global(global::Global), HookEnv(hook_env::HookEnv), @@ -228,6 +230,7 @@ impl Commands { Self::En(cmd) => cmd.run(), Self::Env(cmd) => cmd.run(), Self::Exec(cmd) => cmd.run(), + Self::Format(cmd) => cmd.run(), Self::Generate(cmd) => cmd.run(), Self::Global(cmd) => cmd.run(), Self::HookEnv(cmd) => cmd.run(), diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index 80b10916c0..9061168ae1 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -992,6 +992,23 @@ const completionSpec: Fig.Spec = { } ] }, + { + "name": [ + "format", + "fmt" + ], + "description": "Formats mise.toml", + "options": [ + { + "name": [ + "-a", + "--all" + ], + "description": "Format all files from the current directory", + "isRepeatable": false + } + ] + }, { "name": [ "generate",