Skip to content

Add implementation of match arm alignment #1704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from

Conversation

Ruin0x11
Copy link

This is a draft of the "match_align_arms" functionality described in #894. Regression tests are included.

@nrc
Copy link
Member

nrc commented Jun 17, 2017

Thanks for implementing this, it looks pretty good! I have a few high level comments:

I'd prefer to avoid a Preserve option. As a rule I have found it creates difficulties to take into account the original formatting rather than relying purely on the abstract representation. I see the motivation for Preserve - some times vertical alignment makes more sense than others. However, I think we could do better. Perhaps use a heuristic for the maximum amount of whitespace introduced? Or apply only to matches where every arm is single line? It might be worth looking at some examples of where you definitely don't want vertical alignment and seeing if that suggests a rule.

I'm a bit surprised by how much whitespace is introduced. I would expect that the longest pattern always gets exactly one space before the expression, e.g.,

match lorem {
    Lorem::Ipsum => (),
    Lorem::Dolor => (),
    Lorem::Sit   => (),
    Lorem::Amet  => (),
}

Is there a reason not to?

@Ruin0x11
Copy link
Author

Ruin0x11 commented Jun 17, 2017

Yes, I agree that it should always reformat to the minimum amount of spacing. I'll make that change. As for Preserve, I agree that it does make sense to use a heuristic to not reformat sometimes, like in this case:

match lorem {
    Lorem::Ipsum => {
        lorem();
        ipsum();
    },
    Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (),
    Lorem::Eiusmod => {
        lorem();
        ipsum();
    },
}

It would add a lot of unnecessary whitespace to the other statements.

@Ruin0x11
Copy link
Author

Ruin0x11 commented Jun 17, 2017

I replaced Preserve with a Conservative option and added the config option match_arm_align_threshold. Now if a match statement has patterns with a difference in width greater than match_arm_align_threshold (default 10) with the Conservative option, they won't be reformatted:

match lorem {
    Lorem::Ipsum => (),
    Lorem::Dolor => (),
    Lorem::Sit => (),
    Lorem::Amet => (),
}

match lorem {
    Lorem::Ipsum => {
        lorem();
        ipsum();
    },
    Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (),
    Lorem::Eiusmod => {
        lorem();
        ipsum();
    },
}

becomes:

match lorem {
    Lorem::Ipsum => (),
    Lorem::Dolor => (),
    Lorem::Sit   => (),
    Lorem::Amet  => (),
}


match lorem {
    Lorem::Ipsum => {
        lorem();
        ipsum();
    },
    Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (),
    Lorem::Eiusmod => {
        lorem();
        ipsum();
    },
}

@nrc
Copy link
Member

nrc commented Jun 18, 2017

Could we have just a single config option like match_arm_align_threshold - 0 would mean never align, a large number (say == max_width) would mean always align, and anything in between would be conservative?

@Ruin0x11
Copy link
Author

Sure, sounds good to me.

@@ -222,6 +222,8 @@ pub struct Shape {
// Indentation + any already emitted text on the first line of the current
// statement.
pub offset: usize,
// Alignment to other structures
pub alignment: usize,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than add this to Shape, can you pass this as an extra arg to the relevant functions?

@nrc
Copy link
Member

nrc commented Jun 19, 2017

@topecongiro would you be able to give this a review please?

@Ruin0x11 also needs rebasing before we can merge

@topecongiro
Copy link
Contributor

@nrc Sure!
@Ruin0x11 I have not tested myself, but I wonder whether the BytePos based alignment works even when the patterns are multi-lined. Could you add tests for those cases?

@Ruin0x11
Copy link
Author

I added the tests, and as expected they don't. However I'm wondering what the best way of getting the relative position is using only each arm.

@topecongiro
Copy link
Contributor

topecongiro commented Jun 23, 2017

@Ruin0x11 Do you have any updates?
I am afraid that using span to calculate the alignment is not a good idea, since the horizontal length may change after rewriting the pattern. The following snippet is an example.

    let x = match op {
        Some(Foo(  ..  )) => 0,
        None => 1,
    };

I think we have to first rewrite all the patterns and calculate the alignment using those results.

@Ruin0x11
Copy link
Author

Yes, that was the same conclusion I came to. This turned out to be way harder than I imagined.

@topecongiro
Copy link
Contributor

@Ruin0x11 In case you are not interested in to this anymore, please let me know.

@Ruin0x11
Copy link
Author

Ruin0x11 commented Jul 3, 2017

I think I'll open another PR when I can resolve the above issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants