Skip to content

[Feature request] Annotations to ignore sections of code #1704

Open
@amongonz

Description

@amongonz

I propose we support annotations in code to ignore certain sections from formatting. This is helpful for code known to trigger soundness bugs in Fantomas or sections that benefit from unusual formatting.

Looking at other formatters for inspiration, I see different annotations we could use for this:

  • Prettier (JS) uses comments like // prettier-ignore to exclude the next AST element from formatting. I think this is clever, although it can take more effort to get right.
  • Rider, IDEA and Eclipse exclude sections between comments // @formatter:off/on.
  • Roslyn excludes sections between #pragma warning disable/restore format. In F# this could be a directive #format disable/restore, but it'd raise a warning at compile time unless a language suggestion was made so the compiler recognises it.
  • A crude alternative could also be #if !FANTOMAS ... #endif.

The existing way Fantomas deals with this problem is by ignoring the entire file with .fantomasignore.

Pros and Cons

The advantage of making this adjustment to Fantomas is having an escape hatch for excluding small sections of code, specially to work around soundness bugs.

The disadvantage of making this adjustment to Fantomas is having to scan comments for annotations and track which nodes should be formatted. It could also interfact badly with existing soundness bugs around comments.

Examples

Using Prettier-like annotations and default settings. Before:

// fantomas-ignore
module Ignored =
    let bar=2
    let baz   x =  [x,2,3]

module Formatted =
    let bar=2
    let baz   x =  [x,2,3]

let ignoredPoint x   y=
    (* fantomas-ignore *){|X=x;    Y=y|}

let point x   y=
    {|X=x;    Y=y|}

After:

// fantomas-ignore
module Ignored =
    let bar=2
    let baz   x =  [x,2,3]

module Formatted =
    let bar = 2
    let baz x = [ x, 2, 3 ]

let ignoredPoint x y =
    (* fantomas-ignore *) {|X=x;    Y=y|}

let point x y = {| X = x; Y = y |}

The formatting of the syntax elements following fantomas-ignore comments has been ignored. Open questions are whether inner let/use are counted as an element or only their binding part and what precedence does it have respect to F# operators.

Using Rider-style annotations and default settings. Before:

let normalizeIgnored key   xs  =
    // @formatter:off
    let firstValue = xs |> Seq.find (fun (y,v) -> y = key) |> snd
    xs |> Seq.map (fun (y,v) -> (y, float v / firstValue) )
    // @formatter:on

let normalize key   xs  = 
    let firstValue = xs |> Seq.find (fun (y,v) -> y = key) |> snd
    xs |> Seq.map (fun (y,v) -> (y, float v / firstValue) )

After:

let normalizeIgnored key xs =
    // @formatter:off
    let firstValue = xs |> Seq.find (fun (y,v) -> y = key) |> snd
    xs |> Seq.map (fun (y,v) -> (y, float v / firstValue) )
    // @formatter:on

let normalize key xs =
    let firstValue =
        xs |> Seq.find (fun (y, v) -> y = key) |> snd

    xs
    |> Seq.map (fun (y, v) -> (y, float v / firstValue))

(Fantomas currently moves // @formatter:on to the first column.) The formatting of nodes between formatter:off and formatter:on comments has been ignored. #format disable/restore would behave similarly.

Extra information

Estimated cost (XS, S, M, L, XL, XXL): M/L, probably depends on which annotation syntax is chosen.

Affidavit (please submit!)

Please tick this by placing a cross in the box:

Please tick all that apply:

  • This is not a breaking change to Fantomas
  • I would be willing to help implement and/or test this
  • This suggestion is part of the Microsoft style guide (please add a link to section if so)
  • This suggestion is part of the G-Research style guide (please add a link to section if so)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions