Coder Social home page Coder Social logo

nix-community / nixpkgs-fmt Goto Github PK

View Code? Open in Web Editor NEW
553.0 12.0 33.0 3.91 MB

Nix code formatter for nixpkgs [maintainer=@zimbatm]

Home Page: https://nix-community.github.io/nixpkgs-fmt/

License: Apache License 2.0

Rust 67.99% Nix 27.76% Shell 1.10% HTML 3.14%
nix formatter rust-crate nixpkgs cli pre-commit-hook

nixpkgs-fmt's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nixpkgs-fmt's Issues

sample: output converges after 2 tries

This sample takes two tries to stabilize

Input

{
  buildInputs = [
  ] ++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
    ++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
  ;
}

Output

{
  buildInputs = []
  ++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
  ++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
  ;
}

After feeding the output back as an input:

{
  buildInputs = []
    ++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
    ++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
    ;
}

NUR package?

I currently have added it to my namespace:

$ nix-shell -p nur.repos.mic92.nixpkgs-fmt
$ nixpkgs-fmt --help
nixpkgs-fmt 0.1
Format Nix code

USAGE:
    nixpkgs-fmt [FLAGS] [OPTIONS] [FILE]

FLAGS:
    -h, --help        Prints help information
    -i, --in-place    Overwrite FILE in place
        --parse       Show syntax tree instead of reformatting
    -V, --version     Prints version information

OPTIONS:
    -o, --output <file>    Place the output into <file>

ARGS:
    <FILE>    File to reformat

However it might be useful to have it might useful to have it a namespace
managed by one of the maintainers. Otherwise you can always make a pull request to my repository ...

sample: balanced let block

It would better if the body was balanced with the set entries when the let block is not on the root of the file:

Input

{
  myAttr = foo:
    let
 hello = 3; in hello;
}

Output

{
  myAttr = foo:
    let
      hello = 3;
    in
    hello;
}

Desired output

{
  myAttr = foo:
    let
      hello = 3;
    in
      hello;
}

sample: multi-line parenthesis

When a parenthesis is multi-line it should indent the inner bits.

Input

{
  xxx = listToAttrs (
  concatMap (name:
    let a = 4; in 5
));
}

Output

{
  xxx = listToAttrs (
  concatMap (name:
    let a = 4; in 5
  ));
}

Desired output

{
  xxx = listToAttrs (
    concatMap (name:
      let a = 4; in 5
    )
  );
}

multi-line string is indented wrong in paranthese

(let
  a = ''
    foo
  '';
 in a)

results in

(
  let
    a = ''
      foo
      '';
  in
    a
)

instead of

(
  let
    a = ''
      foo
    '';
  in
    a
)

a more practical example would be:

wpa_supplicant.overrideAttrs(old: {
  postBuild = ''
    echo foo
  '';
})

->

wpa_supplicant.overrideAttrs (
  old: {
    postBuild = ''
      echo foo
      '';
  }
)

sample: normalize indentation to tabs or spaces

Input

let
  pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz))  {});
in
pkgs.buildEnv {
  name = "innovu-httpd";
  paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
  postBuild = ''
    # no tabs
		# tabs
  '';
}

Output

let
  pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz)) {});
in
pkgs.buildEnv {
  name = "innovu-httpd";
  paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
  postBuild = ''
        # no tabs
    		# tabs
  '';
}

Desired output

Ideally the output should confirm to whatever the nix language specifies or the conventions of nixpkgs. I don't really care whether it is tabs or spaces. The below uses spaces just to show the indentation consistency in GitHub's markdown code block:

let
  pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz))  {});
in
pkgs.buildEnv {
  name = "innovu-httpd";
  paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
  postBuild = ''
    # no tabs
    # tabs
  '';
}

remove line break after expanded let ... in

# One line, everyone's happy
let self = { }; in self

#65 (comment) suggests that we could consider let ... in just as an assert ...; or a with ... ; statement that does not indent the following body. In that case example 2 is inconsistent.

# input
# This should be okay if `let` is considered like a `with` or `assert` 
let self = { }; in
self
# nix-fmt output
# But it is expanded :-(
let
  self = {};
in
self

Overall, it seems that the let ... in body is expanded (split across multiple lines as long as it is not written on one line. I think that expanding the let ... in part should be independent from expanding the body itself and from decoupling the in from the body.

The above example is made even worse by the fact that we do not indent toplevel let bodies (#108). The self really looks weird and could be on the same line as the in.

May I propose the following patterns ?

let foo = bar; in foo
let foo = bar; in
foo
let
  foo = bar;
in {
  bar = foo;
}

The implicit rule is that when the let+in construct is one one line, it behaves like a with or assert, and when it is on several lines (expanded form), no line break is enforced after the in (which means that line breaks are only enforced for a multi-line body after a single line let+in).

sample:

Input

{config,pkgs, lib      =wfp}: {}

Output

{ config, pkgs, lib      =wfp }: {}

Desired output

{ config, pkgs, lib = wfp }: {}

Avoid opening a scope for parentheses and for single-element lists.

Looking at the diff produced by @zimbatm on discourse, the main differences that I see are on using compact forms to avoid extra lines.
For example:

diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
index 7ff22fb61fa..87d2ca3aa43 100644
--- a/maintainers/maintainer-list.nix
+++ b/maintainers/maintainer-list.nix
@@ -51,10 +51,12 @@
     name = "Joachim Ernst";
     github = "0x4A6F";
     githubId = 9675338;
-    keys = [{
-      longkeyid = "rsa8192/0x87027528B006D66D";
-      fingerprint = "F466 A548 AD3F C1F1 8C88  4576 8702 7528 B006 D66D";
-    }];
+    keys = [
+      {
+        longkeyid = "rsa8192/0x87027528B006D66D";
+        fingerprint = "F466 A548 AD3F C1F1 8C88  4576 8702 7528 B006 D66D";
+      }
+    ];
   };
   "1000101" = {
     email = "[email protected]";

and this occurs in many places, like for fetch* calls

diff --git a/pkgs/development/python-modules/pyscard/default.nix b/pkgs/development/python-modules/pyscard/default.nix
index bab8e502b9c..e601f23ada9 100644
--- a/pkgs/development/python-modules/pyscard/default.nix
+++ b/pkgs/development/python-modules/pyscard/default.nix
@@ -19,10 +19,12 @@ buildPythonPackage rec {
   patches = [
     # Fixes darwin tests
     # See: https://github.com/LudovicRousseau/pyscard/issues/77
-    (fetchpatch {
-      url = "https://github.com/LudovicRousseau/pyscard/commit/62e675028086c75656444cc21d563d9f08ebf8e7.patch";
-      sha256 = "1lr55npcpc8j750vf7vaisqyk18d5f00l7nii2lvawg4sssjaaf7";
-    })
+    (
+      fetchpatch {
+        url = "https://github.com/LudovicRousseau/pyscard/commit/62e675028086c75656444cc21d563d9f08ebf8e7.patch";
+        sha256 = "1lr55npcpc8j750vf7vaisqyk18d5f00l7nii2lvawg4sssjaaf7";
+      }
+    )
   ];

There seems to be an implicit rule that collapsing delimiters (parentheses, square brackets and such) is desirable if there is only one expression inside. Furthermore, the collapsing results in a single indent, instead of two (or more).

In short:

Input

{ 
  testA= [(fetchurl {
  url = "bla";
})];

 testB = [( fetchurl{url="bla";} )];
}

Output

{
  testA = [
    (
      fetchurl {
        url = "bla";
      }
    )
  ];

  testB = [ (fetchurl { url = "bla"; }) ];
}

Desired output

{
  testA = [ 
    (fetchurl {
      url = "bla";
    })
  ];

  testB = [ (fetchurl { url = "bla"; }) ];
}

or

{
  testA = [ (fetchurl {
    url = "bla";
  }) ];

  testB = [ (fetchurl { url = "bla"; }) ];
}

or (mind the space changes)

{
  testA = [(fetchurl {
    url = "bla";
  })];

  testB = [ (fetchurl { url = "bla"; }) ];
}

Of course, when the list constains mutiple elements, we should switch to a safer form.

Input

{ 
  testA= [(fetchurl {
  url = "bla";
})(fetchurl {
  url = "foo";
})];

 testB = [( fetchurl{url="bla";} )( fetchurl{url="foo";} )];
}

Output

{
  testA = [
    (
      fetchurl {
        url = "bla";
      }
    )
    (
      fetchurl {
        url = "foo";
      }
    )
  ];

  testB = [ (fetchurl { url = "bla"; }) (fetchurl { url = "foo"; }) ];
}

Desired output

{
  testA = [
    (fetchurl {
      url = "bla";
    })
    (fetchurl {
      url = "foo";
    })
  ];

  testB = [ (fetchurl { url = "bla"; }) (fetchurl { url = "foo"; }) ];
}

The simplest way to achieve this would be to make parentheses special. When they are expanded (split on several lines) do not force a line break after them. that would still keep the following desired output impossible, but get all the other options above right.

{
  testA = [(fetchurl {
    url = "bla";
  })];

  testB = [ (fetchurl { url = "bla"; }) ];
}

sample: function argument comments

src/rules.rs apply_arg should probably also look if the node is a comment:

Input

{
  foo =
    # describe bar
    bar:
    # describe baz
    baz:
      fnbody;
}

Output

{
  foo =
  # describe bar
      bar:
      # describe baz
          baz:
            fnbody;
}

Desired output

See input

sample: indented let body

whenever a let..in block is being added, it re-indents the whole body, creating a lot of noise in the diff.

Maybe it's worth special-casing at least for the top-level to not indent the body?

Input

{ stdenv, fetchFromGitHub }:
let
pname = "hello";
version = "1.2.3";
in
stdenv.mkDerivation {
  inherit pname version;
  src = fetchFromGitHub {
    owner = "xxx";
    repo = pname;
    rev = version;
    sha256 = "...";
  };
}

Output

{ stdenv, fetchFromGitHub }:
let
  pname = "hello";
  version = "1.2.3";
in
  stdenv.mkDerivation {
    inherit pname version;
    src = fetchFromGitHub {
      owner = "xxx";
      repo = pname;
      rev = version;
      sha256 = "...";
    };
  }

Desired output

{ stdenv, fetchFromGitHub }:
let
  pname = "hello";
  version = "1.2.3";
in
stdenv.mkDerivation {
  inherit pname version;
  src = fetchFromGitHub {
    owner = "xxx";
    repo = pname;
    rev = version;
    sha256 = "...";
  };
}

Design the CLI

There are essentially two modes of operation for the CLI:

  • on a buffer: takes a buffer in with some nix code, outputs a formatted nix code
  • on a dir: scan all the nix files in a folder and format them. with options to ignore some folders like .git

sample:

Input

{
      inherit (import ./pep425.nix {
        inherit lib python;
        inherit (pkgs) stdenv;
      }) selectWheel;
}

Output

{
  inherit (import ./pep425.nix {
    inherit lib python;
    inherit (pkgs) stdenv;
  }) selectWheel
    ;
}

Desired output

{
  inherit (import ./pep425.nix {
    inherit lib python;
    inherit (pkgs) stdenv;
  }) selectWheel;
}

The ; should not be on a separate line.

trace: assert failed: hash mismatch for file '/nix/store/7jaw5xi1f5nbhbyfhzasvkzgaws03f9q-master.tar.gz/Cargo.lock':

Describe the bug

nix-env -f https://github.com/nix-community/nixpkgs-fmt/archive/master.tar.gz -i
trace: assert failed: hash mismatch for file '/nix/store/7jaw5xi1f5nbhbyfhzasvkzgaws03f9q-master.tar.gz/Cargo.lock':
  wanted: sha256:d6e3edd1c5e96ea40c8ffe5fedf110ad7e903a478d4ae999186023819388f8cb
  got:    sha256:36f58d1ddf4d56bc75aa1d18bb7c4e894eb56c2a0f4a81d83c3f24aec2e98926

System information

  • system: "x86_64-linux"
  • host os: Linux 4.19.66, NixOS, 19.09.git.4557b9f (Loris)
  • multi-user?: yes
  • sandbox: yes
  • version: nix-env (Nix) 2.2.2
  • channels(root): "nixos-19.09pre188498.4557b9f1f50"
  • channels(bbigras2): "home-manager"
  • nixpkgs: /nix/var/nix/profiles/per-user/root/channels/nixos

sample: unindented `++`s after a new line

Input

pkgs.example rec {
  buildInputs = [ pkgs.foo  ] ++
    pkgs.stdenv.lib.optionals pkgs.stdenv.isDarwin [
      pkgs.bar
    ];
}

Output

pkgs.example rec {
  buildInputs = [ pkgs.foo ]
  ++ pkgs.stdenv.lib.optionals pkgs.stdenv.isDarwin [ # <- I'm surprised this isn't indentend two spaces
    pkgs.bar
  ]
  ;
}

Not so sure about this one, though.

sample: wrap if statements

Input

if true==1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234 then foo else bar

Output

if true == 1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234 then foo else bar

Desired output

if
  true == 1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234
then foo
else bar

if statements that are too long should be wrapped

Github Pages version of the WASM formatter doesn't load a needed JS file

I am so excited for this. I tried out the existing version on master at https://nix-community.github.io/nixpkgs-fmt/ and it fails to load a javascript file.

The script from โ€œhttps://nix-community.github.io/nixpkgs-fmt/pkg/nixpkgs_fmt_wasm.jsโ€ was loaded even though its MIME type (โ€œtext/htmlโ€) is not a valid JavaScript MIME type.[Learn More] nixpkgs-fmt
Loading failed for the module with source โ€œhttps://nix-community.github.io/nixpkgs-fmt/pkg/nixpkgs_fmt_wasm.jsโ€. nixpkgs-fmt:54:1

โ€‹
at this time the file 404s.

Way to go on the WASM idea. This is incredible.

Debug mode

It would be cool if the engine could should all the matching rules with the diff. The more rule we add, the harder it becomes to understand how they interact with each-other.

Example output:

<rule name> matched <element>
<diff>

What do you think @matklad ?

Build failure on Darwin

On Darwin "cargo build" fails with the following error message:

  = note: ld: framework not found Security
          clang-7: error: linker command failed with exit code 1 (use -v to see invocation)

I think that darwin.apple_sdk.frameworks.Security should be added to the buildInputs.

sample: if statement after key

Input

{
  userHome = if home != null
    then home
    else config.users.extraUsers.${user}.home;
}

Output

{
  userHome = if home != null
  then home
  else config.users.extraUsers.${user}.home;
}

Desired output

{
  userHome = if home != null
    then home
    else config.users.extraUsers.${user}.home;
}

or maybe

{
  userHome =
    if home != null
    then home
    else config.users.extraUsers.${user}.home;
}

sample: function body indent

I think the function body shouldn't be indented if the arguments are on the same level.

Input

let
  aaa =
 {foo,bar}:
              foo+bar
;
bbb = {foo,bar}:
              foo+bar
;
in
  null

Output

let
  aaa =
    { foo, bar }:
      foo + bar
  ;
  bbb = { foo, bar }:
    foo + bar
  ;
in
null

Desired output

let
  aaa =
    { foo, bar }:
    foo + bar
    ;
  bbb = { foo, bar }:
    foo + bar
    ;
in
null

sample: Weirdly closed brace in attribute set default in function arguments

Input

{
  pkgs ? import ./nix/nixpkgs.nix { },
  src ? builtins.fetchGit {
    url = ./.;
    ref = "HEAD";
  }
}:
pkgs.example rec {
}

Output

{ pkgs ? import ./nix/nixpkgs.nix {}
, src ? builtins.fetchGit {
  url = ./.;
  ref = "HEAD";
} # <- it seems this } and the two prior lines should be indented
}:
pkgs.example rec {
}

Haskell comma in function parameters

I see two different patterns which are used to format function arguments:

  1. Haskell comma:
{ pkgs ? import ./nix/nixpkgs.nix {}
, src ? builtins.fetchGit {
    url = ./.;
    ref = "HEAD";
  }
}:
pkgs.example rec {}
  1. More traditional, with comma after the pattern:
  toINI = {
    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
    mkKeyValue    ? mkKeyValueDefault {} "="
  }: attrsOfAttrs:
    let ...

which one we should use?

Additionally, is it a good idea to to keep first parameter on the same line, as in { pkgs ? import ./nix/nixpkgs.nix {} ?

URLs and paths

We should rewrite URLs like http://example.com to string "http://example.com"

Should we do the same for paths like ./some/dir? Or are paths and urls are completely different things? rnix uses TOKEN_PATH for both of these, and I wonder if that should be fixed.

indentation of buildInputs is very odd

Not sure what the proper way to do this would be, but the nested indentation is not right.

Input

{ mkDerivation }:

mkDerivation rec {

  buildInputs = [
    alsaLib
  ]  ++ lib.optionals stdenv.isLinux [
     utillinux
  ] ++ (with gst_all_1; [
     gstreamer
  ]);
}

Output

{ mkDerivation }:

mkDerivation rec {

  buildInputs = [
    alsaLib
  ]
    ++ lib.optionals stdenv.isLinux [
         utillinux
       ]
    ++ (
         with gst_all_1; [
           gstreamer
         ]
       )
    ;
}

Desired output

{ mkDerivation }:

mkDerivation rec {

  buildInputs = [
    alsaLib
  ]
  ++ lib.optionals stdenv.isLinux [
    utillinux
  ]
  ++ (with gst_all_1; [
    gstreamer
  ])
  ;
}

sample: Multiline comments cause an inconsistent amount of items per line

Just played around in the WASM example a little.

Input

[ one /*two*/ three four five six seven eight nine
]

Output

[
  one /*two*/ three
  four
  five
  six
  seven
  eight
  nine
]

Desired output

[
  one /*two*/
  three
  four
  five
  six
  seven
  eight
  nine
]

or maybe even the comment should be on its own line, not sure.

sample:

Input

{
  inherit (builtins)
    # comment
    toString
    ;
}

Output

{
  inherit (builtins) # comment toString;
}

Expected output

{
  inherit (builtins)
    # comment
    toString
    ;
}

RuntimeError: unreachable executed

Describe the bug

Formatting this code produces a runtime error:

{ } =

To Reproduce
Steps to reproduce the behavior:

  1. Run echo "{} =" > sample.nix
  2. Run `nixpkgs-fmt ./sample.nix'
thread 'main' panicked at 'assertion failed: prev.is_none()', src/engine/fmt_model.rs:267:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

Expected behavior
No runtime error

System information

nixpkgs-fmt version: master 81e2341

sample: demo for @nbp

Input

# NixOS module handling.

let lib = import ./default.nix; in

with { inherit (builtins) head tail; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
with import ./properties.nix;

rec {

  # Unfortunately this can also be a string.
  isPath = x: !(
     builtins.isFunction x
  || builtins.isAttrs x
  || builtins.isInt x
  || builtins.isBool x
  || builtins.isList x
  );

  importIfPath = path:
    if isPath path then
      import path
    else
      path;

  applyIfFunction = f: arg:
    if builtins.isFunction f then
      f arg
    else
      f;

  moduleClosure = initModules: args:
    let
      moduleImport = m:
        (applyIfFunction (importIfPath m) args) // {
          # used by generic closure to avoid duplicated imports.
          key = m;
        };

      removeKeys = list: map (m: removeAttrs m ["key"]) list;

      getImports = m:
        if m ? config || m ? options then
          attrByPath ["imports"] [] m
        else
          toList (rmProperties (attrByPath ["require"] [] (delayProperties m)));

      getImportedPaths = m: filter isPath (getImports m);
      getImportedSets = m: filter (x: !isPath x) (getImports m);

      inlineImportedSets = list:
        lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list;
    in
      removeKeys (inlineImportedSets (lazyGenericClosure {
        startSet = map moduleImport initModules;
        operator = m: map moduleImport (getImportedPaths m);
      }));

  selectDeclsAndDefs = modules:
    lib.concatMap (m:
      if m ? config || m ? options then
         attrByPath ["options"] [] m
      ++ attrByPath ["config"] [] m
      else
        [ m ]
    ) modules;

}

Output

# NixOS module handling.

let
  lib = import ./default.nix;
in

with { inherit (builtins) head tail; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
with import ./properties.nix;

rec {

  # Unfortunately this can also be a string.
  isPath = x: !(
    builtins.isFunction x
    || builtins.isAttrs x
    || builtins.isInt x
    || builtins.isBool x
    || builtins.isList x
  );

  importIfPath = path:
    if isPath path then
      import path
    else
      path;

  applyIfFunction = f: arg:
    if builtins.isFunction f then
      f arg
    else
      f;

  moduleClosure = initModules: args:
    let
      moduleImport = m:
        (applyIfFunction (importIfPath m) args)
        // {
             # used by generic closure to avoid duplicated imports.
             key = m;
           };

      removeKeys = list: map (m: removeAttrs m [ "key" ]) list;

      getImports = m:
        if m ? config || m ? options then
          attrByPath [ "imports" ] [] m
        else
          toList (rmProperties (attrByPath [ "require" ] [] (delayProperties m)));

      getImportedPaths = m: filter isPath (getImports m);
      getImportedSets = m: filter (x: !isPath x) (getImports m);

      inlineImportedSets = list:
        lib.concatMap (m:[ m ] ++ map moduleImport (getImportedSets m)) list;
    in
    removeKeys (
      inlineImportedSets (
        lazyGenericClosure {
          startSet = map moduleImport initModules;
          operator = m: map moduleImport (getImportedPaths m);
        }
      )
    );

  selectDeclsAndDefs = modules:
    lib.concatMap (
      m:
        if m ? config || m ? options then
          attrByPath [ "options" ] [] m
          ++ attrByPath [ "config" ] [] m
        else
          [ m ]
    ) modules;

}

Desired output

sample: `++` folding

nixpkgs-fmt should respect \n and never fold lines back into one

Input

foo ++
bar

Output

foo ++ bar

Desired output

foo
++ bar

Fuzzing crash 654e6ed06597b86f23483b793664777da9b24c04

Describe the bug
Fuzzing crash: fuzz/artifacts/fmt/crash-654e6ed06597b86f23483b793664777da9b24c04

To Reproduce
Steps to reproduce the behavior:

  1. Run echo ".." > foo.nix
  2. Run `nixpkgs-fmt foo.nix'
thread 'main' panicked at 'assertion failed: prev.is_none()', src/engine/fmt_model.rs:269:9

Scientific notation is corrupted

Describe the bug
nixpkgs-fmt changes the meaning of scientific notation.

To Reproduce

Format the following expression:

3.9e-3

It will format this as

3.9 e-3

which is not the same expression.

Expected behavior

The file is unchanged

System information

  • nixpkgs-fmt --version

nixpkgs-fmt 0.6.0

Additional context
Add any other context about the problem here.

sample: multi-line strings should be balanced

The multi-line string should behave more like the list [ and ]

Input

{
  string =          ''
hello
'';
  list = [
hello
];
}

Output

{
  string = ''
    hello
    '';
  list = [
    hello
  ];
}

Desired output

{
  string = ''
    hello
  '';
  list = [
    hello
  ];
}

sample: text block is not formatted correctly

Input

{ lib, ... }:

with lib;

{
  nix.extraOptions = ''
    builders-use-substitutes = true
  '';
}

Output

{ lib, ... }:

with lib;

  {
    nix.extraOptions = ''
    builders-use-substitutes = true
  '';
  }

Expected

    nix.extraOptions = ''
    	builders-use-substitutes = true
  	'';

WASM Demo: show diff

I tested it with a package i created, but see no diff. So maybe my code is perfect (i hope :D), but i might not see the diff. So it would be helpful to highlight the diff.

attset indentation issue

Another variation of #20. This is the diff I am getting on a correctly-formatted code:

   catAttrs = builtins.catAttrs or
-    (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
+  (attr: l: concatLists (map (s: if s ? ${attr} then [ s.${attr} ] else []) l));

Still fighting the same conflict we have with keeping the balanced trees.

Provide 'validate' option

Is your feature request related to a problem? Please describe.
I usually use formaters / linters in pre-commit hooks to prevent mal-formatted commits but I dislike for the formatter to manipulate the git index by formatting changed files. Instead, I prefer running in linter mode that can fail the hook with exit code != 0 in case of formatting issues. The point of this is that I prefer to review the change before committing it. nixpkgs-fmt lacks such a mode.

Describe the solution you'd like
A command option nixpkgs-fmt --validate [srcs] that takes a list of files and fails if one or more files are not properly formatted.

Describe alternatives you've considered
I suppose you can achieve this using bash scripting, eg (pseudo-code)

for file in $(find . -name "*.nix"); do
  cat "$file" | nixpkgs-fmt --explain >  "$file.explain"
  if diff "$file" "$file.explain"; then
    exit 1
  fi 
done
exit 0

This does feel like a hack though.

sample: `builtins.fold' (` causes funky indentation for following arguments

Input

    (
      builtins.foldl' (
        acc: v: let
          isOperator = builtins.typeOf v == "list";
          operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
        in
          if isOperator then (acc // { inherit operator; }) else {
            inherit operator;
            state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
          }
      )
        {
          operator = ",";
          state = true;
        }
        tokens
    ).state;

Output

(
  builtins.foldl' (
    acc: v: let
      isOperator = builtins.typeOf v == "list";
      operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
    in
      if isOperator then (acc // { inherit operator; }) else {
        inherit operator;
        state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
      }
  )
    {
      operator = ",";
      state = true;
    }
    tokens
).state;

Desired output

(
  builtins.foldl'
    (
      acc: v: let
        isOperator = builtins.typeOf v == "list";
        operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
      in
        if isOperator then (acc // { inherit operator; }) else {
          inherit operator;
          state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
        }
    )
    {
      operator = ",";
      state = true;
    }
    tokens
).state;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.