Skip to content

Fix: lambda formatting #497

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

Merged
merged 3 commits into from
Aug 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions packages/prettier-plugin-java/src/printers/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import {
} from "java-parser";
import { Doc } from "prettier";
import { isAnnotationCstNode, isTypeArgumentsCstNode } from "../types/utils";
import { printArgumentListWithBraces } from "../utils";

const { line, softline, hardline } = builders;

Expand Down Expand Up @@ -734,16 +735,16 @@ export class ClassesPrettierVisitor extends BaseCstPrettierPrinter {
) {
const typeArguments = this.visit(ctx.typeArguments);
const keyWord = ctx.This ? ctx.This[0] : ctx.Super![0];
const argumentList = this.visit(ctx.argumentList);
const argumentList = printArgumentListWithBraces.call(
this,
ctx.argumentList,
ctx.RBrace![0],
ctx.LBrace[0]
);
return rejectAndConcat([
typeArguments,
keyWord,
group(
rejectAndConcat([
putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace[0]),
ctx.Semicolon[0]
])
)
group(rejectAndConcat([argumentList, ctx.Semicolon[0]]))
]);
}

Expand All @@ -752,19 +753,19 @@ export class ClassesPrettierVisitor extends BaseCstPrettierPrinter {
) {
const expressionName = this.visit(ctx.expressionName);
const typeArguments = this.visit(ctx.typeArguments);
const argumentList = this.visit(ctx.argumentList);
const argumentList = printArgumentListWithBraces.call(
this,
ctx.argumentList,
ctx.RBrace![0],
ctx.LBrace[0]
);

return rejectAndConcat([
expressionName,
ctx.Dot[0],
typeArguments,
ctx.Super[0],
group(
rejectAndConcat([
putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace[0]),
ctx.Semicolon[0]
])
)
group(rejectAndConcat([argumentList, ctx.Semicolon[0]]))
]);
}

Expand Down Expand Up @@ -842,18 +843,22 @@ export class ClassesPrettierVisitor extends BaseCstPrettierPrinter {
const otherModifiers = this.mapVisit(modifiers[1]);

const identifier = ctx.Identifier[0];
const argumentList = this.visit(ctx.argumentList);
const classBody = this.visit(ctx.classBody);

const optionnalBracesAndArgumentList = ctx.LBrace
? putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace![0])
const optionalBracesAndArgumentList = ctx.LBrace
? printArgumentListWithBraces.call(
this,
ctx.argumentList,
ctx.RBrace![0],
ctx.LBrace[0]
)
: "";

return rejectAndJoin(hardline, [
rejectAndJoin(hardline, firstAnnotations),
rejectAndJoin(" ", [
rejectAndJoin(" ", otherModifiers),
rejectAndConcat([identifier, optionnalBracesAndArgumentList]),
rejectAndConcat([identifier, optionalBracesAndArgumentList]),
classBody
])
]);
Expand Down
118 changes: 89 additions & 29 deletions packages/prettier-plugin-java/src/printers/expressions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use strict";

import { BaseCstPrettierPrinter } from "../base-cst-printer";
import {
ArgumentListCtx,
ArrayAccessSuffixCtx,
Expand Down Expand Up @@ -50,40 +49,64 @@ import {
} from "java-parser/api";

import forEach from "lodash/forEach";
import { concat, group, indent, dedent } from "./prettier-builder";
import { Doc } from "prettier";
import { builders } from "prettier/doc";
import { BaseCstPrettierPrinter } from "../base-cst-printer";
import { isAnnotationCstNode } from "../types/utils";
import { isArgumentListSingleLambda } from "../utils/expressions-utils";
import {
printSingleLambdaInvocation,
printArgumentListWithBraces
} from "../utils";
import { printTokenWithComments } from "./comments/format-comments";
import { handleCommentsBinaryExpression } from "./comments/handle-comments";
import { concat, dedent, group, indent } from "./prettier-builder";
import {
matchCategory,
rejectAndJoin,
rejectAndConcat,
sortAnnotationIdentifier,
sortNodes,
rejectAndJoinSeps,
findDeepElementInPartsArray,
isExplicitLambdaParameter,
isShiftOperator,
isUniqueMethodInvocation,
matchCategory,
putIntoBraces,
rejectAndConcat,
rejectAndJoin,
rejectAndJoinSeps,
separateTokensIntoGroups,
isShiftOperator,
isUniqueMethodInvocation
sortAnnotationIdentifier,
sortNodes
} from "./printer-utils";
import { builders } from "prettier/doc";
import { Doc } from "prettier";
import { isAnnotationCstNode, isCstNode } from "../types/utils";
const { ifBreak, line, softline } = builders;

const { ifBreak, line, softline, indentIfBreak } = builders;

export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
expression(ctx: ExpressionCtx, params: any) {
return this.visitSingle(ctx, params);
}

lambdaExpression(ctx: LambdaExpressionCtx) {
const lambdaParameters = this.visit(ctx.lambdaParameters);
lambdaExpression(
ctx: LambdaExpressionCtx,
params?: {
lambdaParametersGroupId: symbol;
isInsideMethodInvocationSuffix: boolean;
}
) {
const lambdaParameters = group(
this.visit(ctx.lambdaParameters, params),
params ? { id: params.lambdaParametersGroupId } : undefined
);
const lambdaBody = this.visit(ctx.lambdaBody);

const isLambdaBodyABlock = ctx.lambdaBody[0].children.block !== undefined;
if (isLambdaBodyABlock) {
return rejectAndJoin(" ", [lambdaParameters, ctx.Arrow[0], lambdaBody]);
return rejectAndJoin(" ", [
lambdaParameters,
ctx.Arrow[0],
params?.lambdaParametersGroupId !== undefined
? indentIfBreak(lambdaBody, {
groupId: params.lambdaParametersGroupId
})
: lambdaBody
]);
}

return group(
Expand All @@ -96,23 +119,35 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
);
}

lambdaParameters(ctx: LambdaParametersCtx) {
lambdaParameters(
ctx: LambdaParametersCtx,
params?: { isInsideMethodInvocationSuffix: boolean }
) {
if (ctx.lambdaParametersWithBraces) {
return this.visitSingle(ctx);
return this.visitSingle(ctx, params);
}

return printTokenWithComments(this.getSingle(ctx) as IToken);
}

lambdaParametersWithBraces(ctx: LambdaParametersWithBracesCtx) {
lambdaParametersWithBraces(
ctx: LambdaParametersWithBracesCtx,
params?: { isInsideMethodInvocationSuffix: boolean }
) {
const lambdaParameterList = this.visit(ctx.lambdaParameterList);

if (findDeepElementInPartsArray(lambdaParameterList, ",")) {
return rejectAndConcat([
ctx.LBrace[0],
const content = putIntoBraces(
lambdaParameterList,
softline,
ctx.LBrace[0],
ctx.RBrace[0]
]);
);
if (params?.isInsideMethodInvocationSuffix === true) {
return indent(concat([softline, content]));
}

return content;
}

// removing braces when only no comments attached
Expand Down Expand Up @@ -142,7 +177,7 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
inferredLambdaParameterList(ctx: InferredLambdaParameterListCtx) {
const commas = ctx.Comma
? ctx.Comma.map(elt => {
return concat([elt, " "]);
return concat([elt, line]);
})
: [];

Expand All @@ -153,7 +188,7 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
const lambdaParameter = this.mapVisit(ctx.lambdaParameter);
const commas = ctx.Comma
? ctx.Comma.map(elt => {
return concat([elt, " "]);
return concat([elt, line]);
})
: [];
return rejectAndJoinSeps(commas, lambdaParameter);
Expand Down Expand Up @@ -595,15 +630,22 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
const classOrInterfaceTypeToInstantiate = this.visit(
ctx.classOrInterfaceTypeToInstantiate
);
const argumentList = this.visit(ctx.argumentList);

let content = printArgumentListWithBraces.call(
this,
ctx.argumentList,
ctx.RBrace[0],
ctx.LBrace[0]
);

const classBody = this.visit(ctx.classBody);

return rejectAndJoin(" ", [
ctx.New[0],
rejectAndConcat([
typeArguments,
classOrInterfaceTypeToInstantiate,
putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace[0])
content
]),
classBody
]);
Expand Down Expand Up @@ -642,17 +684,35 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter {
}

methodInvocationSuffix(ctx: MethodInvocationSuffixCtx, params: any) {
const isSingleLambda = isArgumentListSingleLambda(ctx.argumentList);
if (isSingleLambda) {
return printSingleLambdaInvocation.call(
this,
ctx.argumentList,
ctx.RBrace[0],
ctx.LBrace[0]
);
}

const argumentList = this.visit(ctx.argumentList);

if (params && params.shouldDedent) {
return dedent(
putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace[0])
);
}

return putIntoBraces(argumentList, softline, ctx.LBrace[0], ctx.RBrace[0]);
}

argumentList(ctx: ArgumentListCtx) {
const expressions = this.mapVisit(ctx.expression);
argumentList(
ctx: ArgumentListCtx,
params?: {
lambdaParametersGroupId: symbol;
isInsideMethodInvocationSuffix: boolean;
}
) {
const expressions = this.mapVisit(ctx.expression, params);
const commas = ctx.Comma ? ctx.Comma.map(elt => concat([elt, line])) : [];
return rejectAndJoinSeps(commas, expressions);
}
Expand Down
37 changes: 37 additions & 0 deletions packages/prettier-plugin-java/src/utils/expressions-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ArgumentListCstNode } from "java-parser";

export function isArgumentListSingleLambda(
argumentList: ArgumentListCstNode[] | undefined
) {
if (argumentList === undefined) {
return false;
}

const args = argumentList[0].children.expression;
if (args.length !== 1) {
return false;
}

const argument = args[0];
return argument.children.lambdaExpression !== undefined;
}

export const isSingleArgumentLambdaExpressionWithBlock = (
argumentList: ArgumentListCstNode[] | undefined
) => {
if (argumentList === undefined) {
return false;
}

const args = argumentList[0].children.expression;
if (args.length !== 1) {
return false;
}

const argument = args[0];
return (
argument.children.lambdaExpression !== undefined &&
argument.children.lambdaExpression[0].children.lambdaBody[0].children
.block !== undefined
);
};
2 changes: 2 additions & 0 deletions packages/prettier-plugin-java/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as printArgumentListWithBraces } from "./printArgumentListWithBraces";
export { default as printSingleLambdaInvocation } from "./printSingleLambdaInvocation";
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ArgumentListCstNode, IToken } from "java-parser";
import { builders } from "prettier/doc";
import { isArgumentListSingleLambda } from "./expressions-utils";
import { putIntoBraces } from "../printers/printer-utils";
import printSingleLambdaInvocation from "./printSingleLambdaInvocation";

const { softline } = builders;

export default function printArgumentListWithBraces(
argumentListCtx: ArgumentListCstNode[] | undefined,
rBrace: IToken,
lBrace: IToken
) {
const isSingleLambda = isArgumentListSingleLambda(argumentListCtx);
if (isSingleLambda) {
return printSingleLambdaInvocation.call(
this,
argumentListCtx,
rBrace,
lBrace
);
}

const argumentList = this.visit(argumentListCtx, {
isInsideMethodInvocationSuffix: true
});
return putIntoBraces(argumentList, softline, lBrace, rBrace);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ArgumentListCstNode, IToken } from "java-parser";
import { builders } from "prettier/doc";
import { isSingleArgumentLambdaExpressionWithBlock } from "./expressions-utils";
import { printTokenWithComments } from "../printers/comments/format-comments";
import { concat, dedent, indent } from "../printers/prettier-builder";
import { putIntoBraces } from "../printers/printer-utils";

const { softline, ifBreak } = builders;

export default function printSingleLambdaInvocation(
argumentListCtx: ArgumentListCstNode[] | undefined,
rBrace: IToken,
lBrace: IToken
) {
const lambdaParametersGroupId = Symbol("lambdaParameters");
const argumentList = this.visit(argumentListCtx, {
lambdaParametersGroupId,
isInsideMethodInvocationSuffix: true
});

const formattedRBrace = isSingleArgumentLambdaExpressionWithBlock(
argumentListCtx
)
? ifBreak(
indent(concat([softline, rBrace])),
printTokenWithComments(rBrace),
{ groupId: lambdaParametersGroupId }
)
: indent(concat([softline, rBrace]));
return dedent(putIntoBraces(argumentList, "", lBrace, formattedRBrace));
}
Loading