1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand, ValueEnum};
4
5#[derive(Debug, Clone, Copy, ValueEnum)]
6pub enum FormatArg {
7 Org,
8 Latex,
9 Markdown,
10 Rst,
11 Plaintext,
12}
13
14#[derive(Debug, Clone, Copy, ValueEnum)]
15pub enum OutputFormat {
16 Text,
17 Json,
18 Sarif,
19}
20
21#[derive(Debug, Parser)]
22#[command(name = "snapper", version, about = "Semantic line break formatter")]
23pub struct Cli {
24 #[command(subcommand)]
25 pub command: Option<Commands>,
26
27 #[arg()]
29 pub files: Vec<PathBuf>,
30
31 #[arg(short, long)]
33 pub format: Option<FormatArg>,
34
35 #[arg(long)]
37 pub stdin_filepath: Option<PathBuf>,
38
39 #[arg(short, long)]
41 pub output: Option<PathBuf>,
42
43 #[arg(short, long)]
45 pub in_place: bool,
46
47 #[arg(short = 'w', long, default_value_t = 0)]
49 pub max_width: usize,
50
51 #[arg(long)]
53 pub neural: bool,
54
55 #[arg(long, default_value = "en")]
58 pub lang: String,
59
60 #[arg(long)]
62 pub model_path: Option<PathBuf>,
63
64 #[arg(long)]
66 pub check: bool,
67
68 #[arg(long)]
70 pub diff: bool,
71
72 #[arg(long)]
74 pub config: Option<PathBuf>,
75
76 #[arg(long)]
78 pub range: Option<String>,
79
80 #[arg(long, default_value = "text")]
82 pub output_format: OutputFormat,
83}
84
85#[derive(Debug, Subcommand)]
86pub enum Commands {
87 Init {
89 #[arg(long)]
91 dry_run: bool,
92 },
93 Sdiff {
95 old: PathBuf,
97 new: PathBuf,
99 #[arg(short, long)]
101 format: Option<FormatArg>,
102 #[arg(long)]
104 no_color: bool,
105 },
106 GitDiff {
108 #[arg(default_value = "HEAD")]
110 git_ref: String,
111 #[arg()]
113 files: Vec<PathBuf>,
114 #[arg(short, long)]
116 format: Option<FormatArg>,
117 #[arg(long)]
119 no_color: bool,
120 },
121 Lsp,
123 Watch {
125 #[arg(required = true)]
127 patterns: Vec<String>,
128 #[arg(short, long)]
130 format: Option<FormatArg>,
131 },
132}
133
134pub fn parse_range(s: &str) -> Option<(usize, usize)> {
136 let parts: Vec<&str> = s.split(':').collect();
137 if parts.len() != 2 {
138 return None;
139 }
140 let start = parts[0].parse::<usize>().ok()?;
141 let end = parts[1].parse::<usize>().ok()?;
142 if start == 0 || end == 0 || start > end {
143 return None;
144 }
145 Some((start, end))
146}