plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


cca230ePeter John 2026-07-19T17:36:59+05:30
feat: add plum-cli binary with format subcommand
plum-cli/Cargo.toml CHANGED
@@ -3,5 +3,11 @@ name = "plum-cli"
3
3
  version = "0.1.0"
4
4
  edition = "2021"
5
5
 
6
+ [[bin]]
7
+ name = "plum"
8
+ path = "src/main.rs"
9
+
6
10
  [dependencies]
7
11
  plum-core = { path = "../plum-core" }
12
+ clap = { version = "4", features = ["derive"] }
13
+ anyhow = "1"
plum-cli/src/lib.rs DELETED
@@ -1 +0,0 @@
1
- // plum-cli library placeholder
plum-cli/src/main.rs ADDED
@@ -0,0 +1,79 @@
1
+ use std::fs;
2
+ use std::io::{self, Read};
3
+ use std::process;
4
+
5
+ use anyhow::{Context, Result};
6
+ use clap::{Parser, Subcommand};
7
+
8
+ use plum_core::format_source;
9
+
10
+ #[derive(Parser)]
11
+ #[command(name = "plum", about = "The Plum language toolchain")]
12
+ struct Cli {
13
+ #[command(subcommand)]
14
+ command: Command,
15
+ }
16
+
17
+ #[derive(Subcommand)]
18
+ enum Command {
19
+ /// Format a Plum source file
20
+ Format {
21
+ /// File to format (omit to use --stdin)
22
+ file: Option<std::path::PathBuf>,
23
+ /// Check if file is formatted; exit 1 if it would change
24
+ #[arg(long)]
25
+ check: bool,
26
+ /// Read from stdin and write formatted source to stdout
27
+ #[arg(long)]
28
+ stdin: bool,
29
+ },
30
+ }
31
+
32
+ fn main() {
33
+ if let Err(e) = run() {
34
+ eprintln!("error: {e:#}");
35
+ process::exit(1);
36
+ }
37
+ }
38
+
39
+ fn run() -> Result<()> {
40
+ let cli = Cli::parse();
41
+ match cli.command {
42
+ Command::Format { file, check, stdin } => cmd_format(file, check, stdin),
43
+ }
44
+ }
45
+
46
+ fn cmd_format(
47
+ file: Option<std::path::PathBuf>,
48
+ check: bool,
49
+ use_stdin: bool,
50
+ ) -> Result<()> {
51
+ if use_stdin {
52
+ let mut source = String::new();
53
+ io::stdin()
54
+ .read_to_string(&mut source)
55
+ .context("failed to read stdin")?;
56
+ let formatted = format_source(&source).map_err(|e| anyhow::anyhow!("{e}"))?;
57
+ print!("{formatted}");
58
+ return Ok(());
59
+ }
60
+
61
+ let path = file.ok_or_else(|| anyhow::anyhow!("provide a file path or --stdin"))?;
62
+ let source =
63
+ fs::read_to_string(&path).with_context(|| format!("failed to read {}", path.display()))?;
64
+ let formatted = format_source(&source).map_err(|e| anyhow::anyhow!("{e}"))?;
65
+
66
+ if check {
67
+ if source != formatted {
68
+ eprintln!("{}: would reformat", path.display());
69
+ process::exit(1);
70
+ }
71
+ return Ok(());
72
+ }
73
+
74
+ if source != formatted {
75
+ fs::write(&path, formatted.as_bytes())
76
+ .with_context(|| format!("failed to write {}", path.display()))?;
77
+ }
78
+ Ok(())
79
+ }