···6677use std::io;
8899-use crate::{
1010- err::{FixErr, StatixErr},
1111- traits::WriteDiagnostic,
1212-};
99+use crate::{err::{StatixErr, FixErr}, traits::WriteDiagnostic};
13101411use clap::Clap;
1515-use config::{FixConfig, LintConfig, Opts, SubCommand};
1212+use config::{FixConfig, LintConfig, Opts};
1613use similar::TextDiff;
17141815fn _main() -> Result<(), StatixErr> {
1916 let opts = Opts::parse();
2020- match opts.subcmd {
2121- Some(SubCommand::Fix(_)) => {
2222- let fix_config = FixConfig::from_opts(opts)?;
2323- let vfs = fix_config.vfs()?;
2424- for entry in vfs.iter() {
2525- match fix::fix(entry.contents) {
2626- Ok(fix_result) => {
2727- let text_diff = TextDiff::from_lines(entry.contents, &fix_result.src);
2828- let old_file = format!("{}", entry.file_path.display());
2929- let new_file = format!("{} [fixed]", entry.file_path.display());
3030- println!(
3131- "{}",
3232- text_diff
3333- .unified_diff()
3434- .context_radius(4)
3535- .header(&old_file, &new_file)
3636- );
3737- }
3838- Err(e) => eprintln!("{}", FixErr::Parse(entry.file_path.to_path_buf(), e)),
1717+ if opts.fix {
1818+ let fix_config = FixConfig::from_opts(opts)?;
1919+ let vfs = fix_config.vfs()?;
2020+ for entry in vfs.iter() {
2121+ if let Some(fix_result) = fix::fix(entry.contents) {
2222+ if fix_config.diff_only {
2323+ let text_diff = TextDiff::from_lines(entry.contents, &fix_result.src);
2424+ let old_file = format!("{}", entry.file_path.display());
2525+ let new_file = format!("{} [fixed]", entry.file_path.display());
2626+ println!(
2727+ "{}",
2828+ text_diff
2929+ .unified_diff()
3030+ .context_radius(4)
3131+ .header(&old_file, &new_file)
3232+ );
3333+ } else {
3434+ let path = entry.file_path;
3535+ std::fs::write(path, &*fix_result.src).map_err(FixErr::InvalidPath)?;
3936 }
4037 }
4138 }
4242- None => {
4343- let lint_config = LintConfig::from_opts(opts)?;
4444- let vfs = lint_config.vfs()?;
4545- let (lints, errors): (Vec<_>, Vec<_>) =
4646- vfs.iter().map(lint::lint).partition(Result::is_ok);
4747- let lint_results = lints.into_iter().map(Result::unwrap);
4848- let errors = errors.into_iter().map(Result::unwrap_err);
3939+ } else {
4040+ let lint_config = LintConfig::from_opts(opts)?;
4141+ let vfs = lint_config.vfs()?;
4242+ let (lints, errors): (Vec<_>, Vec<_>) = vfs.iter().map(lint::lint).partition(Result::is_ok);
4343+ let lint_results = lints.into_iter().map(Result::unwrap);
4444+ let errors = errors.into_iter().map(Result::unwrap_err);
49455050- let mut stderr = io::stderr();
5151- lint_results.for_each(|r| {
5252- stderr.write(&r, &vfs, lint_config.format).unwrap();
5353- });
5454- errors.for_each(|e| {
5555- eprintln!("{}", e);
5656- });
5757- }
4646+ let mut stdout = io::stdout();
4747+ lint_results.for_each(|r| {
4848+ stdout.write(&r, &vfs, lint_config.format).unwrap();
4949+ });
5050+ errors.for_each(|e| {
5151+ eprintln!("{}", e);
5252+ });
5853 }
5954 Ok(())
6055}
+45-4
readme.md
···11-## statix
11+# statix
22+33+> Lints and suggestions for the Nix programming language.
2433-`statix` intends to be a static analysis tool for the
44-Nix programming language.
55+`statix` highlights antipatterns in Nix code. `statix fix`
66+can fix several such occurrences.
5768For the time-being, `statix` works only with ASTs
79produced by the `rnix-parser` crate and does not evaluate
810any nix code (imports, attr sets etc.).
9111212+## Installation
1313+1414+`statix` is available via a nix flake:
1515+1616+```
1717+nix run git+https://git.peppe.rs/languages/statix
1818+1919+# or
2020+2121+nix build git+https://git.peppe.rs/languages/statix
2222+./result/bin/statix --help
2323+```
2424+2525+## Usage
2626+2727+```
2828+statix 0.1.0
2929+3030+Akshay <nerdy@peppe.rs>
3131+3232+Lints and suggestions for the Nix programming language
3333+3434+USAGE:
3535+ statix [FLAGS] [OPTIONS] [--] [TARGET]
3636+3737+ARGS:
3838+ <TARGET> File or directory to run statix on [default: .]
3939+4040+FLAGS:
4141+ -d, --dry-run Do not fix files in place, display a diff instead
4242+ -f, --fix Find and fix issues raised by statix
4343+ -h, --help Print help information
4444+ -V, --version Print version information
4545+4646+OPTIONS:
4747+ -i, --ignore <IGNORE>... Globs of file patterns to skip
4848+ -o, --format <FORMAT> Output format. Supported values: errfmt, json (on feature flag only)
4949+```
5050+1051## Architecture
11521253`statix` has the following components:
···3778## TODO
38793980- Offline documentation for each lint
4040-- Automatically fix all lints from suggestions generated
4181- Test suite for lints and suggestions
8282+- Output singleline/errfmt + vim plugin