Giter Club home page Giter Club logo

Comments (12)

dungpa avatar dungpa commented on July 19, 2024

On #10, @xenocons said:

@dungpa I like that preferences section, a lot could be added (especially this parenthesis reduction). I am also wondering:

  1. With curly braces is it criminal to keep them on the same line as the function name? e.g:
let arec = {
  x = 1
  y = 2 
}

You don't gain or lose a line, but what you do gain is less indentation so you save page width space.

  1. What are your thoughts on vertical alignment? It costs you page width but can make the code more readable. e.g.
let saturn = { 
    X    =  8.343366718
    Y    =  4.124798564
    Z    = -0.4035234171
    VX   = -0.002767425107  * daysPerYear
    VY   =  0.004998528012  * daysPerYear
    VZ   =  2.304172976e-05 * daysPerYear
    Mass =  0.0002858859807 * solarMass 
}

I couldn't get github to indent my record elements sorry! but hopefully you get the idea.

from fantomas.

dungpa avatar dungpa commented on July 19, 2024

Answer:

  1. I don't think it is a good idea. A more common style I saw is

    let s = seq {
        for i in 1..4 -> i * i
    }

    where there is an indentation on inner constructs. The argument is if you remove brackets, indentation is still correct.

  2. From tool implementer 's point of view, alignment is possible for = but not possible for numbers and *. The reason is that appearance of = is fixed while you don't know whether you will use numbers or * in record fields or not.

I'm still not convinced that field alignment should be supported. Hope to hear other voices on this.

from fantomas.

vasily-kirichenko avatar vasily-kirichenko commented on July 19, 2024

+1 for

let s = seq {
    for i in 1..4 -> i * i
}

Space between function/class name and the the open parenthesis:

let f(x: int) = x

type t(x : int) = 
    class
    end

->

let f (x: int) = x

type t (x: int) = 
    class 
    end

Space before constructor arguments:

type t (x : int) = 
    class
    end

->

type t (x: int) = 
    class
    end

Do not separate one-liners with an empty line:

let b = a |> Option.map ((*) 3) 

let b' = ((*) 3) <!> a 

->

let b = a |> Option.map ((*) 3) 
let b' = ((*) 3) <!> a 

Do not break short list/array/seq declarations:

let files = 
    ["c:\\Test1.txt"
     "c:\\Test2.txt"]

->

let files = [ "c:\\Test1.txt"; "c:\\Test2.txt" ]

from fantomas.

dungpa avatar dungpa commented on July 19, 2024

@vasily-kirichenko Your 2nd and 3rd examples are achieved by setting SpaceBeforeArgument = true and SpaceBeforeColon = false. I will update type constructors' arguments soon to be consistent with function arguments.

Regarding your 4th example, it's not cheap to test for one-liners, so I defer it for now. I will come back to it when I have a chance to implement.

About the last example, it is already working for numbers. It's harder for strings since strings could be multiple lines and there are several kinds of strings (verbatim, triple-quote, multiline ones, etc) so it's not easy to implement it. But of course, I would also like to do so as soon as I can.

from fantomas.

vasily-kirichenko avatar vasily-kirichenko commented on July 19, 2024

OK, 2 and 3 really work :) Thanks.
Some more suggestions:

  • Do not realign one-line type declarations if they fit into Config.PageWidth
// current
type R = 
    { F1: int;
      F2: string }
type U = 
    | C1
    | C2
    | C3
// desired
type R = { F1: int; F2: string }
type U = C1 | C2 | C3
  • Surround with blank lines those type members that are more than one line long
// current
type C () = 
    let x = 1
    let y = 3
    let f () = 
        let x = 1
        let y = 2
        x + y
    let z = 4
// desired
type C () = 
    let x = 1
    let y = 3

    let f () = 
        let x = 1
        let y = 2
        x + y

    let z = 4
  • Preserve try...with...finally one-liners
// current
let f () = 
    try 
        1 + 1
        |> ignore
    with
        | _ -> ()
// desired
let f () = try 1 + 1 |> ignore with _ -> ()

from fantomas.

dungpa avatar dungpa commented on July 19, 2024
  • 3rd example:
    Again it's the matter of detecting one-liners. I'll keep an eye on this.

  • 2nd example:
    I'll implement it in v0.9.2. Now it's clear to me what the requirement is.

  • 1st example:
    The reason we always give a line break is that

    type U = C1 | C2 | C3
          member _.Val = ()

    fails to compile (you need to add with before member) while

    type U = 
        | C1 | C2 | C3
        member _.Val = ()

    does.

    Should I include a line break if type declaration contains members and write them one-liner if not?

    The fields could be written in the same line. I just wonder what are qualified for one-liner declaration? In case of DUs, are those the ones that can easily be converted to enums?

from fantomas.

vasily-kirichenko avatar vasily-kirichenko commented on July 19, 2024

Interesting, I didn't know about differences between "with member..." and just "member". So, I suggest the following:

// UNFORMATTED 

type U1 = 
    | C1 
    | C2 
    | C3
    member __.Val = ()

type U2 = C1 | C2 | C3
      with member __.Val = ()

type U3 = 
    C1 | C2 | C3
    member __.Val = ()

type U4 = C1 | C2 | C3

type U5 = C1 | C2 | C3 // when it exceeds PageWidth

// FORMATTED

// not touch
type U1 = 
    | C1 
    | C2 
    | C3
    member __.Val = ()

// add a a line brake and remove "with"
type U2 = 
    C1 | C2 | C3
    member __.Val = ()

// not touch 
type U3 = 
    C1 | C2 | C3 // or | C1 | C2 | C3 - not sure what is better 
    member __.Val = ()

// not touch
type U4 = C1 | C2 | C3

// add a line break 
type U5 = 
    | C1 
    | C2 
    | C3

from fantomas.

dungpa avatar dungpa commented on July 19, 2024

The problem is that U1, U2 and U3 have the same parse tree. It makes sense to choose one format that works for every case.

According to current implementation, when U5 exceeds one line, it will be transform into something like

type U5 = | C1 | C2 
          | C3

I'm not sure it is a good thing to implement.

If we would like to estimate lengths of all cases and write each in a separate line, a major change is needed.

from fantomas.

vasily-kirichenko avatar vasily-kirichenko commented on July 19, 2024

Another suggestion. Do not rearrange multi-line expression if it's splitted by operators:

// current
let form = 
    Formlet.Yield (fun x y -> x + " " + y) <*> Controls.Select 0 ["p1", "1"
                                                                  "p2", "2"] <*> Controls.Input ""
    |> Enhance.WithLegend "Label"

// desired
let form =
    Formlet.Yield (fun x y -> x + " " + y)
    <*> Controls.Select 0 ["p1", "1"; "p2", "2" ]
    <*> Controls.Input ""
    |> Enhance.WithLegend "Label"

from fantomas.

dungpa avatar dungpa commented on July 19, 2024

Thanks for the suggestion. What is your definition of multi-line expression?

In your example, only Controls.Select is a multi-line expression. If we treat it differently, we arrive at

let form =
    Formlet.Yield (fun x y -> x + " " + y)
    <*> Controls.Select 0 ["p1", "1"; 
                           "p2", "2" ] <*> Controls.Input ""
    |> Enhance.WithLegend "Label"

Your desired example can be achieved by using <*> as a multi-line operator. The problem is that some time users would like it to be multi-line, sometimes they don't.

At the moment, we have a fixed set of multi-line operators which consists of only piping operators (|>, ||>, etc) (see https://github.com/dungpa/fantomas/blob/master/src/Fantomas/FormatConfig.fs#L288).

Should I expose this set as a configuration and let users add new infix operators if they want?

from fantomas.

vasily-kirichenko avatar vasily-kirichenko commented on July 19, 2024

I think the root of this issue is that Fantomas does not respect initial format at all (it looses it when transforms the code into AST). I don't think that configurable list of supported infix operators is a good solution.
The proper solution, I think, is taking into account the initial format, i.e., if the user use an operator as multi-line one, Fantomas should preserve it; if do not, then break long lines to fit into PageWidth (preferring infix operators as points to break, if possible).

from fantomas.

dungpa avatar dungpa commented on July 19, 2024

I understand the limitation. I explained it in my blog post http://lonelypad.blogspot.dk/2013/04/developing-source-code-formatter-for-f.html

I tried to find references for solving formatting problems for whitespace-sensitive languages but I had no luck. As much as I like a full-range solution, it isn't practical yet. In this regard, F# suffers from the same problem as Python does.

The solution would be a clever mixture of lexer-based and parser-based approach. Until we sort out the solution, the goal is to format all F# constructs in a consistent and correct way.

from fantomas.

Related Issues (20)

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.