diff --git a/CHANGELOG.md b/CHANGELOG.md index e8015963a7..73ce10beba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - A little performance improvement for JSX V4 runtime helper by removing one object allocation for components with key prop. https://github.com/rescript-lang/rescript-compiler/pull/6376 - The error message for "toplevel expressions should evaluate to unit" has been revamped and improved. https://github.com/rescript-lang/rescript-compiler/pull/6407 - Improve "Somewhere wanted" error messages by changing wording and adding more context + suggested solutions to the error messages where appropriate. https://github.com/rescript-lang/rescript-compiler/pull/6410 +- Add smart printer for pipe-chains. https://github.com/rescript-lang/rescript-compiler/pull/6411 # 11.0.0-rc.3 diff --git a/jscomp/gentype/TranslateStructure.ml b/jscomp/gentype/TranslateStructure.ml index 66185837fc..7919fcd042 100644 --- a/jscomp/gentype/TranslateStructure.ml +++ b/jscomp/gentype/TranslateStructure.ml @@ -11,8 +11,7 @@ let rec addAnnotationsToTypes_ ~config ~(expr : Typedtree.expression) let aName = if aName = "*opt*" then match arg_label with - | Optional l -> - l + | Optional l -> l | _ -> "" (* should not happen *) else aName in @@ -56,6 +55,7 @@ and addAnnotationsToFields ~config (expr : Typedtree.expression) in ({field with nameJS = name} :: nextFields1, types1) | _ -> (fields, argTypes) + [@@live] (** Recover from expr the renaming annotations on named arguments. *) let addAnnotationsToFunctionType ~config (expr : Typedtree.expression) diff --git a/jscomp/syntax/src/res_printer.ml b/jscomp/syntax/src/res_printer.ml index abd0811093..f85094a7c7 100644 --- a/jscomp/syntax/src/res_printer.ml +++ b/jscomp/syntax/src/res_printer.ml @@ -3527,8 +3527,8 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = Doc.concat [spacingBeforeOperator; Doc.text operatorTxt; spacingAfterOperator] in - let printOperand ~isLhs expr parentOperator = - let rec flatten ~isLhs expr parentOperator = + let printOperand ~isLhs ~isMultiline expr parentOperator = + let rec flatten ~isLhs ~isMultiline expr parentOperator = if ParsetreeViewer.isBinaryExpression expr then match expr with | { @@ -3541,7 +3541,7 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = ParsetreeViewer.flattenableOperators parentOperator operator && not (ParsetreeViewer.hasAttributes expr.pexp_attributes) then - let leftPrinted = flatten ~isLhs:true left operator in + let leftPrinted = flatten ~isLhs:true ~isMultiline left operator in let rightPrinted = let rightPrinteableAttrs, rightInternalAttrs = ParsetreeViewer.partitionPrintableAttributes @@ -3585,12 +3585,26 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = Doc.rparen; ] else - Doc.concat - [ - leftPrinted; - printBinaryOperator ~inlineRhs:false operator; - rightPrinted; - ] + match operator with + | ("|." | "|.u") when isMultiline -> + (* If the pipe-chain is written over multiple lines, break automatically + * `let x = a->b->c -> same line, break when line-width exceeded + * `let x = a-> + * b->c` -> pipe-chain is written on multiple lines, break the group *) + Doc.breakableGroup ~forceBreak:true + (Doc.concat + [ + leftPrinted; + printBinaryOperator ~inlineRhs:false operator; + rightPrinted; + ]) + | _ -> + Doc.concat + [ + leftPrinted; + printBinaryOperator ~inlineRhs:false operator; + rightPrinted; + ] in let doc = @@ -3665,7 +3679,7 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = | Braced braces -> printBraces doc expr braces | Nothing -> doc) in - flatten ~isLhs expr parentOperator + flatten ~isLhs ~isMultiline expr parentOperator in match expr.pexp_desc with | Pexp_apply @@ -3679,8 +3693,8 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = || ParsetreeViewer.isBinaryExpression rhs || printAttributes ~state expr.pexp_attributes cmtTbl <> Doc.nil) -> let lhsHasCommentBelow = hasCommentBelow cmtTbl lhs.pexp_loc in - let lhsDoc = printOperand ~isLhs:true lhs op in - let rhsDoc = printOperand ~isLhs:false rhs op in + let lhsDoc = printOperand ~isLhs:true ~isMultiline:false lhs op in + let rhsDoc = printOperand ~isLhs:false ~isMultiline:false rhs op in Doc.group (Doc.concat [ @@ -3697,12 +3711,16 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = | Pexp_apply ( {pexp_desc = Pexp_ident {txt = Longident.Lident operator}}, [(Nolabel, lhs); (Nolabel, rhs)] ) -> + let isMultiline = + lhs.pexp_loc.loc_start.pos_lnum < rhs.pexp_loc.loc_start.pos_lnum + in + let right = let operatorWithRhs = let rhsDoc = printOperand ~isLhs:(ParsetreeViewer.isRhsBinaryOperator operator) - rhs operator + ~isMultiline rhs operator in Doc.concat [ @@ -3722,7 +3740,7 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl = [ printOperand ~isLhs:(not @@ ParsetreeViewer.isRhsBinaryOperator operator) - lhs operator; + ~isMultiline lhs operator; right; ]) in diff --git a/jscomp/syntax/tests/printer/expr/expected/callback.res.txt b/jscomp/syntax/tests/printer/expr/expected/callback.res.txt index 50393c396b..4e04e8a787 100644 --- a/jscomp/syntax/tests/printer/expr/expected/callback.res.txt +++ b/jscomp/syntax/tests/printer/expr/expected/callback.res.txt @@ -215,13 +215,16 @@ let f = () => { } -myPromise->Js.Promise.then_(value => { +myPromise +->Js.Promise.then_(value => { Js.log(value) Js.Promise.resolve(value + 2) -}, _)->Js.Promise.then_(value => { +}, _) +->Js.Promise.then_(value => { Js.log(value) Js.Promise.resolve(value + 3) -}, _)->Js.Promise.catch(err => { +}, _) +->Js.Promise.catch(err => { Js.log2("Failure!!", err) Js.Promise.resolve(-2) }, _) diff --git a/jscomp/syntax/tests/printer/expr/expected/smartPipe.res.txt b/jscomp/syntax/tests/printer/expr/expected/smartPipe.res.txt new file mode 100644 index 0000000000..f67034fc4e --- /dev/null +++ b/jscomp/syntax/tests/printer/expr/expected/smartPipe.res.txt @@ -0,0 +1,33 @@ +let myFunc = (strA, strB) => strA ++ strB + +"expr1"->myFunc("expr2")->myFunc("expr3") + +"expr1" +->myFunc("expr2") +->myFunc("expr3") + +"expr1" +->myFunc("expr2") +->myFunc("expr3") + +"expr1" +->myFunc("expr2") +->myFunc("expr3") +->myFunc("expr4") + +myPromise->Promise.then(v => { + Js.log(v) + Promise.resolve(v) +}) + +myPromise->Promise.then(v => { + Js.log(v) + Promise.resolve(v) +}) + +let messages = React.useMemo(() => + messagesById + ->StringMap.valuesToArray + ->Array.filter(ChatMessage.isVisibleInSimpleFilter) + ->Array.toSorted(ChatMessage.compareByDateAsc) +, [messagesById]) diff --git a/jscomp/syntax/tests/printer/expr/smartPipe.res b/jscomp/syntax/tests/printer/expr/smartPipe.res new file mode 100644 index 0000000000..0f1d03531f --- /dev/null +++ b/jscomp/syntax/tests/printer/expr/smartPipe.res @@ -0,0 +1,31 @@ +let myFunc = (strA, strB) => strA ++ strB + +"expr1"->myFunc("expr2")->myFunc("expr3") + +"expr1" +->myFunc("expr2")->myFunc("expr3") + +"expr1"->myFunc("expr2") +->myFunc("expr3") + +"expr1"->myFunc("expr2") +->myFunc("expr3")->myFunc("expr4") + +myPromise->Promise.then(v => { + Js.log(v) + Promise.resolve(v) +}) + +myPromise +->Promise.then(v => { + Js.log(v) + Promise.resolve(v) +}) + +let messages = React.useMemo(() => + messagesById + ->StringMap.valuesToArray + ->Array.filter(ChatMessage.isVisibleInSimpleFilter) + ->Array.toSorted(ChatMessage.compareByDateAsc) +, [messagesById]) +