Announcing `purs-tidy`: a syntax tidy-upper for PureScript

Hey, everyone! I’m really excited to announce an initial (0.x) release of purs-tidy: a syntax tidy-upper for PureScript.

I call it a tidy-upper because it’s pretty forgiving, so I don’t know if I’d go so far as to say it will strictly format your code, but it’ll shore-up all the edges! I expect it to be used with defaults, but it does support some configuration.

  • Turn unicode on or off, or print as-is
  • Arrow-last (purty) style, or arrow-first in type signatures.
  • Some configuration that dodo supports (indent, page-width, ribbon-width).

It has some nice features as well:

  • It’s written completely in PureScript!
  • Supports operator precedence configuration. Ships with a default precedence table based on core/contrib, but you can generate your own for your project if you’ve got lots of operators.
  • Supports parallelism, so it can format your codebase over multiple workers.

There’s still quite a few rough edges, but I’ve been able to run it over my work codebase, and everything continues to compile! :laughing: It’s performance is usable, but not stellar (in absolute terms). Our codebase is 150K+ lines of code, and it formats it in about 11 seconds on my 6 year old laptop.

Again, this is just an initial release (0.x), so a lot may change and improve. I hope y’all enjoy it!

Special thanks to @thomashoneyman and @colinwahl for providing lots of feedback, help with CI, and for pushing me to actually release it :slight_smile:.

31 Likes

I should also mention that I’ve tried to keep it very high-level. If it doesn’t suit your exact needs, I hope it’s easy enough for you to fork and tweak!

5 Likes

yes, another purescript tooling thank you the effort :smiling_face_with_three_hearts:

1 Like

@natefaubion Could you add some documentation about the differences between this, purty and the Yoga pose project?

I’m loving that the package.json has zero dependencies. Good work!

1 Like

I just added it to ALE for Vim with this merge request. I did not bother with the command line options though. My fingers are crossed for the issue I raised about having a configuration dotfile for the project.

Also this fixup request

I’m not totally sure how to answer this, or what information you’d be looking for. I don’t really like directly calling out feature checklist comparisons in my projects. I wrote this because I wanted a formatter written in PureScript that lets me format my work code without having to completely change the style of 150K lines of code :laughing:. tidy is definitely modeled after my work style. I didn’t know pose was a project until after tidy was released. I believe pose is intended to be a PureScript port of purty with fixes for long-standing issues, but I’m not sure what direction the authors intend to take the project.

5 Likes

Ah ha. So that comparison may be better left for a tool comparison showdown or awesome-purescript or the like.

Here’s the formatter being run on the halogen-realworld codebase – not too many changes, and they’re sensible ones!

3 Likes

Used spago2nix to add purs-tidy to easy-purescript-nix with this merge request.

Merged!

1 Like

We just pushed a 0.3.x series which has some nice addtions!

3 Likes

Nice! To what extent is it customizable?
I have run this tool on a few files from my repo, and I see that it mostly decreased indentation when possible (a good thing imo) with some other small changes.
However, for instance, I’m not used to formatting

(...)
  where
  x = 5
  y = 6

I tend to use

(...)
  where
    x = 5
    y = 6

(i.e. x and y declarations indented wrt. to where; sometimes no new line for one short where clause). Is it customizable?

1 Like

I think the where block not indented is more standard in the PureScript community versus the Haskell community. What I’m interested in is what line the project will decide to draw between fully-featured and minimalistic. Perhaps this could be the divide could be the differentiator between this and the Pose project? (though currently neither project allows indented where)

1 Like

What does “fully-featured” mean in this context? Do you mean providing knobs for any variation of style? If so, that’s not really my goal.

  • I provide knobs for arrows and unicode, because there are significant portions of the community that use both (generally those that switched to purty, and those that didn’t, for better or for worse).
  • I provide knobs for indentation, because indentation can have a significant effect on usability for authors that may be visually impaired.
  • I provide knobs for width, because it’s useful to be able to reformat code examples for different contexts.

I don’t have an intention of being principled and necessarily transparent about all these choices, because aesthetic choices are so often quite irrational, and I don’t want to constantly debate it :sweat_smile:. I also don’t intend to be the maintainer of every variation of style in the community. Having forks in the code to account for different styles is really quite difficult, and is not a problem that I’m trying to solve. Even arrow-first vs arrow-last was a lot of work to do well. That’s why I’ve tried to keep it very high-level and easy to fork as a project. My recommendation is to largely “just go with it”. I’ve put a lot of effort into making sure the results are consistent and attractive.

3 Likes

Regarding where, if indented where was super common in the community to the point that it’s a deal breaker for a large portion of potential users, I would be inclined to add a knob. But my experience is that it’s not, and you can get a similar effect by adding an extra newline (which tidy lets you do) if you want some separation. My goal isn’t to please everyone, but if a lot of folks think something is a deal-breaker, I would rather provide an option than not.

3 Likes

I pulled the latest version of easy-purescript-nix and ran nix-shell, which updated a lot of things, but purs-tidy won’t run because it can’t find node:

[nix-shell:~/easy-purescript-nix]$ which purs-tidy
/nix/store/03kvc674qi77h7z5661iys0ab8ay914z-purs-tidy-0.3.1/bin/purs-tidy

[nix-shell:~/easy-purescript-nix]$ purs-tidy --version
/usr/bin/env: ‘node’: No such file or directory

Am I missing something?


EDIT: I ran ./tests.bash and it also failed on purs-tidy --version:

# which pscid
/nix/store/3ihz85diby43hickkxkasm7xvix01mp9-node_pscid-2.9.3/bin/pscid
# pscid --version
2.9.3
# which purescript-language-server
/nix/store/6qjazcww500csbzv824faizsccpsk8xz-node_purescript-language-server-0.15.2/bin/purescript-language-server
# which purs-tidy
/nix/store/6hny3mi3sbi9ggkwlrrh2vir591bfgzw-purs-tidy-0.3.1/bin/purs-tidy
# purs-tidy --version
/usr/bin/env: ‘node’: No such file or directory

@toastal (and those writing editor configurations) Would you mind testing out the --config-require flag? I personally think this should be a flag included for those. I added it specifically so that editors only try to format things that have a config file somewhere, but I’m not sure how well it plays with existing tooling since it will rely on the CWD being set to the file in question.

1 Like

I’ll look at this. I had already added node to the nativeBuildInputs which I thought was supposed to make sure dependencies are there at run time. However, I’ve always had node on my $PATH for various scripts.


Ah, heck. I had swapped buildInput and nativeBuildInput which I always forget which is which.


$ which node                                                                                                  
which: no node in ... $NIXPATHSTUFF
$ bat flake.nix                                                                                               
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: flake.nix
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ {
   2   │   inputs = {
   3   │     nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
   4   │     flake-utils.url = "github:numtide/flake-utils";
   5   │     easy-purescript-nix = {
   6   │       url = "github:toastal/easy-purescript-nix/purs-tidy-swap-build-vs-native";
   7   │       flake = false;
   8   │     };
   9   │   };
  10   │ 
  11   │   outputs = { self, nixpkgs, flake-utils, easy-purescript-nix }:
  12   │     flake-utils.lib.eachDefaultSystem (system:
  13   │       let
  14   │         name = "test";
  15   │         pkgs = import nixpkgs { inherit system; };
  16   │         easy-ps = import easy-purescript-nix { inherit pkgs; };
  17   │       in
  18   │       rec {
  19   │         devShell = pkgs.mkShell {
  20   │           inherit name;
  21   │           buildInputs = with pkgs; [
  22   │             easy-ps.purs-tidy
  23   │           ];
  24   │         };
  25   │       }
  26   │     );
  27   │ }
$ nix develop
$ purs-tidy
purs-tidy
    Expected command.

    A tidy-upper for PureScript source code.

    --help,-h             Show this help message.
    --version,-v          Shows the current version.
    
    check                 Check source files are formatted.
    format                Format input over stdin.
    format-in-place       Format source files in place.
    generate-config       Writes a .tidyrc file to the current working directory based
                          on the command line options given.
    generate-operators    Generate an operator precedence table for better operator formatting.
                          Best used with `spago sources`. Prints to stdout.

Merge request in Justin’s repo


Merged :white_check_mark:

1 Like

Just released 0.4.x! Release v0.4.0 · natefaubion/purescript-tidy · GitHub

There have also been lots of small improvements to formatting throughout the 0.3 tags.

4 Likes

Hi,

I hope you don’t mind asking here instead of going to Github but I’m not really sure if this issue is somehow caused by me.

Anyway I’d love to try out tidy and the docs mentioned that purescript-ide should register that formatter in VS.code - sadly for me this does not work - VS code gives me the single choice of purty and if I edit the json config to purs-tidy it complaints about this formatter not being registered.

Does anyone has some hints for me?

1 Like

I don’t know, but maybe you need to update the extension?

1 Like