Skip to main content

nifty_cli/
lib.rs

1//! The Nifty command-line tool, `nf`.
2
3mod build;
4mod check;
5mod create;
6mod dev;
7mod error;
8mod frontend;
9mod lsp;
10mod project;
11mod report;
12mod run;
13#[cfg(test)]
14mod test_support;
15
16use std::path::Path;
17use std::process::ExitCode;
18
19use error::CliError;
20
21const USAGE: &str = "\
22usage: nf <command> [args]
23
24commands:
25  create <name>      create a new app in a folder called <name>
26  run [project]      run an app (default: the current folder)
27  dev [project]      run an app and reload it each time you save, keeping its state
28  check [project]    report errors in a project (default: the current folder)
29  build [project] [--macos | --windows | --linux]
30                     build a native app (default: for this system)
31  lsp                run the language server on stdin and stdout, for editors
32  version            print the version of nf
33
34A project is a folder with a main.nf file, or a single .nf file.";
35
36/// The program has errors, found while checking it or while it ran.
37const EXIT_HAS_ERRORS: u8 = 1;
38const EXIT_USAGE: u8 = 2;
39
40/// Runs `nf` with its command-line arguments, without the program name.
41#[must_use]
42pub fn nf(args: &[&str]) -> ExitCode {
43    let result = match args {
44        ["create", name] => create::run(name),
45        ["run"] => run::run(Path::new(".")),
46        ["run", target] => run::run(Path::new(target)),
47        ["dev"] => dev::run(Path::new(".")),
48        ["dev", target] => dev::run(Path::new(target)),
49        ["check"] => check::run(Path::new(".")),
50        ["check", target] => check::run(Path::new(target)),
51        ["build", args @ ..] => build::run(args),
52        ["lsp"] => lsp::run(),
53        ["help" | "--help" | "-h"] => {
54            println!("{USAGE}");
55            Ok(ExitCode::SUCCESS)
56        }
57        ["version" | "--version" | "-V"] => {
58            println!("nf {}", env!("CARGO_PKG_VERSION"));
59            Ok(ExitCode::SUCCESS)
60        }
61        _ => {
62            eprintln!("{USAGE}");
63            Ok(ExitCode::from(EXIT_USAGE))
64        }
65    };
66    finish(result)
67}
68
69fn finish(result: CommandResult) -> ExitCode {
70    result.unwrap_or_else(|error| {
71        eprintln!("error: {error}");
72        ExitCode::from(EXIT_USAGE)
73    })
74}
75
76/// Result of a command: the exit code to return, or an error that stopped it.
77type CommandResult = Result<ExitCode, CliError>;