1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
use clap::{Arg, ArgGroup, command, Command, crate_version};

pub const APP_NAME: &str = "GE Helper";

pub mod commands {
    pub const LIST: &str = "list";
    pub const ADD: &str = "add";
    pub const REMOVE: &str = "remove";
    pub const CHECK: &str = "check";
    pub const MIGRATE: &str = "migrate";
    pub const APPLY: &str = "apply";
    pub const PROTON_USER_SETTINGS: &str = "user-settings";
    pub const USER_SETTINGS_COPY: &str = "copy";
    pub const FORGET: &str = "forget";
}

pub mod arg_names {
    pub const LOL_ARG: &str = "lol";
    pub const WINE_ARG: &str = "wine";
    pub const PROTON_ARG: &str = "proton";
    pub const NEWEST_ARG: &str = "newest";
    pub const SKIP_CHECKSUM_ARG: &str = "skip-checksum";
    pub const APPLY_ARG: &str = "apply";
    pub const SOURCE_ARG: &str = "source";
    pub const DESTINATION_ARG: &str = "destination";
}

pub mod arg_group_names {
    pub const TAG: &str = "tag-args";
}

pub mod about_text {
    pub const ADD: &str =
        "Add a GE Proton version for Steam or a Wine GE version for Lutris. If no <TAG> value is provided, the \
         latest version is assumed.";
    pub const LIST: &str = "List available versions.";
    pub const REMOVE: &str =
        r#"Remove a GE Proton version for Steam or a Wine GE version for Lutris. "remove" is aliased to "rm""#;
    pub const CHECK: &str = r#"Check for the latest Github release tags. "check" is aliased to "ck"."#;
    pub const MIGRATE: &str =
        r#"Migrate an existing GE Proton/Wine GE version to make it manageable. "migrate" is aliased to "mg""#;
    pub const APPLY: &str =
        "Apply a Proton GE or Wine GE version by updating the used version in the Steam or Lutris config files.";
    pub const USER_SETTINGS: &str =
        r#"Commands for managing user setting files for Proton versions. "user-settings" is aliased to "us""#;
    pub const USER_SETTINGS_COPY: &str = "Copy a user_settings.py from one Proton version to another.";
    pub const FORGET: &str = "Forget a GE Proton or Wine GE version. This operation does not remove any files.";
}

mod help_text {
    // Add
    pub const ADD_PROTON_TAG: &str = "Download a GE Proton version";
    pub const ADD_WINE_TAG: &str = "Download a Wine GE version";
    pub const ADD_WINE_LOL_TAG: &str = "Download a Wine GE LoL version";
    pub const ADD_SKIP_CHECKSUM: &str = "Skip downloading the checksum and comparing it to the downloaded release.";
    pub const ADD_APPLY: &str = "Set the Steam or Lutris compatibility tool version after successfully adding it.";
    // List
    pub const LIST_PROTON_TAG: &str = "List GE Proton versions";
    pub const LIST_WINE_TAG: &str = "List Wine GE versions";
    pub const LIST_WINE_LOL_TAG: &str = "List Wine GE LoL versions";
    pub const LIST_NEWEST: &str = "List the latest versions for each tag kind.";
    // Remove
    pub const REMOVE_PROTON_TAG: &str = "Remove a GE Proton version";
    pub const REMOVE_WINE_TAG: &str = "Remove a Wine GE version";
    pub const REMOVE_WINE_LOL_TAG: &str = "Remove a Wine GE LoL version";
    // Check
    pub const CHECK_PROTON_TAG: &str = "Check for the latest GE Proton version";
    pub const CHECK_WINE_TAG: &str = "Check for the latest Wine GE version";
    pub const CHECK_WINE_LOL_TAG: &str = "Check for the latest Wine GE LoL version";
    // Migrate
    pub const MIGRATE_PROTON_TAG: &str = "Migrate a GE Proton version";
    pub const MIGRATE_WINE_TAG: &str = "Migrate a Wine GE version";
    pub const MIGRATE_WINE_LOL_TAG: &str = "Migrate a Wine GE LoL version";
    pub const MIGRATE_SOURCE: &str = "Path to a directory containing a Wine GE or Proton GE version.";
    // Apply
    pub const APPLY_PROTON_TAG: &str = "Apply a GE Proton version for Steam";
    pub const APPLY_WINE_TAG: &str = "Apply a Wine GE version for Lutris";
    pub const APPLY_WINE_LOL_TAG: &str = "Apply a Wine GE LoL version for Lutris";
    // User settings copy
    pub const USER_SETTINGS_COPY_SOURCE: &str = "Source tag where to copy the user_settings.py from.";
    pub const USER_SETTINGS_COPY_DESTINATION: &str = "Destination tag where to copy the user_settings.py to.";
    // Forget
    pub const FORGET_PROTON_TAG: &str = "Forget a GE Proton version";
    pub const FORGET_WINE_TAG: &str = "Forget a Wine GE version";
    pub const FORGET_WINE_LOL_TAG: &str = "Forget a Wine GE LoL version";
}

pub mod value_name {
    pub const TAG: &str = "TAG";
    pub const PATH: &str = "PATH";
}

fn proton_arg(help_text: &'static str, min_value: usize) -> Arg {
    Arg::new(arg_names::PROTON_ARG)
        .short('p')
        .long(arg_names::PROTON_ARG)
        .help(help_text)
        .display_order(1)
        .takes_value(true)
        .value_name(value_name::TAG)
        .min_values(min_value)
        .max_values(1)
        .multiple_values(false)
}

fn wine_arg(help_text: &'static str, min_value: usize) -> Arg {
    Arg::new(arg_names::WINE_ARG)
        .short('w')
        .long(arg_names::WINE_ARG)
        .help(help_text)
        .display_order(1)
        .takes_value(true)
        .value_name(value_name::TAG)
        .min_values(min_value)
        .max_values(1)
        .multiple_values(false)
}

fn lol_arg(help_text: &'static str, min_value: usize) -> Arg {
    Arg::new(arg_names::LOL_ARG)
        .short('l')
        .long(arg_names::LOL_ARG)
        .help(help_text)
        .display_order(1)
        .takes_value(true)
        .value_name(value_name::TAG)
        .min_values(min_value)
        .max_values(1)
        .multiple_values(false)
}

fn newest_arg(help_text: &'static str) -> Arg {
    Arg::new(arg_names::NEWEST_ARG)
        .short('n')
        .long(arg_names::NEWEST_ARG)
        .display_order(2)
        .help(help_text)
}

fn skip_checksum_arg(help_text: &'static str) -> Arg {
    Arg::new(arg_names::SKIP_CHECKSUM_ARG)
        .long(arg_names::SKIP_CHECKSUM_ARG)
        .display_order(2)
        .help(help_text)
}

fn apply_arg(help_text: &'static str) -> Arg {
    Arg::new(arg_names::APPLY_ARG)
        .long(arg_names::APPLY_ARG)
        .display_order(2)
        .help(help_text)
}

fn tag_arg_group(required: bool) -> ArgGroup<'static> {
    ArgGroup::new(arg_group_names::TAG)
        .args(&[arg_names::PROTON_ARG, arg_names::WINE_ARG, arg_names::LOL_ARG])
        .required(required)
}

fn setup_list_cmd() -> Command<'static> {
    Command::new(commands::LIST)
        .about(about_text::LIST)
        .version(crate_version!())
        .args(&[
            proton_arg(help_text::LIST_PROTON_TAG, 0).takes_value(false),
            wine_arg(help_text::LIST_WINE_TAG, 0).takes_value(false),
            lol_arg(help_text::LIST_WINE_LOL_TAG, 0).takes_value(false),
            newest_arg(help_text::LIST_NEWEST),
        ])
}

fn setup_add_cmd() -> Command<'static> {
    Command::new(commands::ADD)
        .about(about_text::ADD)
        .version(crate_version!())
        .args(&[
            proton_arg(help_text::ADD_PROTON_TAG, 0),
            wine_arg(help_text::ADD_WINE_TAG, 0),
            lol_arg(help_text::ADD_WINE_LOL_TAG, 0),
            skip_checksum_arg(help_text::ADD_SKIP_CHECKSUM),
            apply_arg(help_text::ADD_APPLY),
        ])
        .group(tag_arg_group(true))
}

fn setup_rm_cmd() -> Command<'static> {
    Command::new(commands::REMOVE)
        .about(about_text::REMOVE)
        .version(crate_version!())
        .alias("rm")
        .args(&[
            proton_arg(help_text::REMOVE_PROTON_TAG, 1),
            wine_arg(help_text::REMOVE_WINE_TAG, 1),
            lol_arg(help_text::REMOVE_WINE_LOL_TAG, 1),
        ])
        .group(tag_arg_group(true))
}

fn setup_check_cmd() -> Command<'static> {
    Command::new(commands::CHECK)
        .about(about_text::CHECK)
        .version(crate_version!())
        .alias("ck")
        .args(&[
            proton_arg(help_text::CHECK_PROTON_TAG, 0).takes_value(false),
            wine_arg(help_text::CHECK_WINE_TAG, 0).takes_value(false),
            lol_arg(help_text::CHECK_WINE_LOL_TAG, 0).takes_value(false),
        ])
        .group(tag_arg_group(false))
}

fn setup_migrate_cmd() -> Command<'static> {
    Command::new(commands::MIGRATE)
        .about(about_text::MIGRATE)
        .version(crate_version!())
        .alias("mg")
        .args(&[
            proton_arg(help_text::MIGRATE_PROTON_TAG, 1),
            wine_arg(help_text::MIGRATE_WINE_TAG, 1),
            lol_arg(help_text::MIGRATE_WINE_LOL_TAG, 1),
        ])
        .arg(
            Arg::new(arg_names::SOURCE_ARG)
                .short('s')
                .long(arg_names::SOURCE_ARG)
                .help(help_text::MIGRATE_SOURCE)
                .required(true)
                .takes_value(true)
                .display_order(1)
                .value_name(value_name::PATH),
        )
        .group(tag_arg_group(true))
}

fn setup_apply_cmd() -> Command<'static> {
    Command::new(commands::APPLY)
        .about(about_text::APPLY)
        .version(crate_version!())
        .args(&[
            proton_arg(help_text::APPLY_PROTON_TAG, 1),
            wine_arg(help_text::APPLY_WINE_TAG, 1),
            lol_arg(help_text::APPLY_WINE_LOL_TAG, 1),
        ])
        .group(tag_arg_group(true))
}

fn setup_user_settings_cmd() -> Command<'static> {
    Command::new(commands::PROTON_USER_SETTINGS)
        .about(about_text::USER_SETTINGS)
        .version(crate_version!())
        .alias("us")
        .subcommand_required(true)
        .subcommand(
            Command::new(commands::USER_SETTINGS_COPY)
                .about(about_text::USER_SETTINGS_COPY)
                .arg(
                    Arg::new(arg_names::SOURCE_ARG)
                        .short('s')
                        .long(arg_names::SOURCE_ARG)
                        .help(help_text::USER_SETTINGS_COPY_SOURCE)
                        .takes_value(true)
                        .required(true)
                        .display_order(1)
                        .value_name(value_name::TAG),
                )
                .arg(
                    Arg::new(arg_names::DESTINATION_ARG)
                        .short('d')
                        .long(arg_names::DESTINATION_ARG)
                        .help(help_text::USER_SETTINGS_COPY_DESTINATION)
                        .takes_value(true)
                        .required(true)
                        .display_order(1)
                        .value_name(value_name::TAG),
                ),
        )
}

fn setup_forget_cmd() -> Command<'static> {
    Command::new(commands::FORGET)
        .about(about_text::FORGET)
        .version(crate_version!())
        .args(&[
            proton_arg(help_text::FORGET_PROTON_TAG, 1),
            wine_arg(help_text::FORGET_WINE_TAG, 1),
            lol_arg(help_text::FORGET_WINE_LOL_TAG, 1),
        ])
        .group(tag_arg_group(true))
}

pub fn setup_clap() -> Command<'static> {
    command!()
        .subcommand_required(true)
        .subcommand(setup_list_cmd())
        .subcommand(setup_add_cmd())
        .subcommand(setup_rm_cmd())
        .subcommand(setup_check_cmd())
        .subcommand(setup_migrate_cmd())
        .subcommand(setup_apply_cmd())
        .subcommand(setup_user_settings_cmd())
        .subcommand(setup_forget_cmd())
}