Skip to content

Commit

Permalink
WIP: JSX text wrapping
Browse files Browse the repository at this point in the history
  • Loading branch information
karl committed Apr 19, 2017
1 parent dc499ba commit ae09ade
Show file tree
Hide file tree
Showing 25 changed files with 358 additions and 305 deletions.
11 changes: 11 additions & 0 deletions src/doc-builders.js
Expand Up @@ -57,6 +57,16 @@ function conditionalGroup(states, opts) {
);
}

function fill(parts) {
if (parts.length === 0) {
return '';
}

parts.forEach(assertDoc);

return { type: "fill", parts };
}

function ifBreak(breakContents, flatContents) {
if (breakContents) {
assertDoc(breakContents);
Expand Down Expand Up @@ -106,6 +116,7 @@ module.exports = {
literalline,
group,
conditionalGroup,
fill,
lineSuffix,
lineSuffixBoundary,
breakParent,
Expand Down
7 changes: 7 additions & 0 deletions src/doc-debug.js
Expand Up @@ -101,6 +101,13 @@ function printDoc(doc) {
);
}

if (doc.type === "fill") {
return ("fill") +
"(" +
doc.parts.map(printDoc).join(", ") +
")";
}

if (doc.type === "line-suffix") {
return "lineSuffix(" + printDoc(doc.contents) + ")";
}
Expand Down
65 changes: 64 additions & 1 deletion src/doc-printer.js
@@ -1,5 +1,12 @@
"use strict";

var docBuilders = require("./doc-builders");
var concat = docBuilders.concat;
var line = docBuilders.line;
var softline = docBuilders.softline;
var fill = docBuilders.fill;
var ifBreak = docBuilders.ifBreak;

const MODE_BREAK = 1;
const MODE_FLAT = 2;

Expand Down Expand Up @@ -30,7 +37,7 @@ function makeAlign(ind, n) {
};
}

function fits(next, restCommands, width) {
function fits(next, restCommands, width, mustBeFlat = false) {
let restIdx = restCommands.length;
const cmds = [next];
while (width >= 0) {
Expand Down Expand Up @@ -70,8 +77,19 @@ function fits(next, restCommands, width) {

break;
case "group":
if (mustBeFlat && doc.break) {
return false;
}
cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);

break;
case "fill":
// include number of spaces
cmds.push([ind, mode, " ".repeat(doc.parts.length - 1)]);
for (var i = doc.parts.length - 1; i >= 0; i--) {
cmds.push([ind, mode, doc.parts[i]]);
}

break;
case "if-break":
if (mode === MODE_BREAK) {
Expand Down Expand Up @@ -210,6 +228,51 @@ function printDocToString(doc, options) {
break;
}
break;
case "fill":
// shouldRemeasure = false;
let rem = width - pos;

const parts = doc.parts;
if (parts.length === 1) {
cmds.push([ind, MODE_BREAK, parts[0]]);
break;
}

const first = parts[0];
const second = parts[1];
const remaining = parts.slice(1);
const firstCmd = [ind, MODE_FLAT, first];
const remainingCmd = [ind, MODE_BREAK, fill(remaining)];

const firstAndSecondCmd = [ind, MODE_FLAT, concat([first, second])];

if (fits(firstAndSecondCmd, cmds, rem, true)) {
// console.log('first and second fit', [first, second]);
cmds.push(remainingCmd)
cmds.push([ind, MODE_FLAT, line]);
cmds.push(firstCmd);
} else if (fits(firstCmd, cmds, width - rem, true)) {
// console.log('only first fits', [first, second]);
cmds.push(remainingCmd)
if (typeof second !== 'string' || typeof first !== 'string') {
cmds.push([ind, MODE_BREAK, "{' '}"]);
}
cmds.push([ind, MODE_BREAK, line]);
cmds.push(firstCmd);
} else {
// console.log('neither fit', [first, second]);
out.push(newLine + " ".repeat(ind));
pos = ind;

cmds.push(remainingCmd);
if (typeof first !== 'string') {
cmds.push([ind, MODE_BREAK, line]);
cmds.push([ind, MODE_BREAK, "{' '}"]);
}
cmds.push([ind, MODE_BREAK, line]);
cmds.push([ind, MODE_BREAK, first]);
}
break;
case "if-break":
if (mode === MODE_BREAK) {
if (doc.breakContents) {
Expand Down
129 changes: 78 additions & 51 deletions src/printer.js
Expand Up @@ -17,6 +17,7 @@ var group = docBuilders.group;
var indent = docBuilders.indent;
var align = docBuilders.align;
var conditionalGroup = docBuilders.conditionalGroup;
var fill = docBuilders.fill;
var ifBreak = docBuilders.ifBreak;
var breakParent = docBuilders.breakParent;
var lineSuffixBoundary = docBuilders.lineSuffixBoundary;
Expand Down Expand Up @@ -2873,62 +2874,88 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
: util.htmlEscapeInsideAngleBracket(child.value);
const value = partiallyEscapedValue.replace(/\u00a0/g, " ");

if (/\S/.test(value)) {
// treat each line of text as its own entity
value.split(/(\r?\n\s*)/).forEach(line => {
const newlines = line.match(/\n/g);
if (newlines) {
children.push(hardline);

// allow one extra newline
if (newlines.length > 1) {
children.push(hardline);
}
return;
}

const beginSpace = /^\s+/.test(line);
if (beginSpace) {
children.push(jsxWhitespace);
children.push(softline);
}
// if (/\S/.test(value)) {
// // treat each line of text as its own entity
// value.split(/(\r?\n\s*)/).forEach(line => {
// const newlines = line.match(/\n/g);
// if (newlines) {
// children.push(hardline);
//
// // allow one extra newline
// if (newlines.length > 1) {
// children.push(hardline);
// }
// return;
// }
//
// const beginSpace = /^\s+/.test(line);
// if (beginSpace) {
// children.push(jsxWhitespace);
// children.push(softline);
// }
//
// const stripped = line.replace(/^\s+|\s+$/g, "");
// if (stripped) {
// children.push(stripped);
// }
//
// const endSpace = /\s+$/.test(line);
// if (endSpace) {
// children.push(softline);
// children.push(jsxWhitespace);
// }
// });
//
// if (!isLineNext(util.getLast(children))) {
// children.push(softline);
// }
// } else if (/\n/.test(value)) {
// children.push(hardline);
//
// // allow one extra newline
// if (value.match(/\n/g).length > 1) {
// children.push(hardline);
// }
// } else if (/\s/.test(value)) {
// // whitespace-only without newlines,
// // eg; a single space separating two elements
// children.push(jsxWhitespace);
// children.push(softline);
// }

value.replace(/^\s+|\s+$/g, "").split(/(\s+)/).forEach(word => {
if (word.length === 0) {
return;
}

const stripped = line.replace(/^\s+|\s+$/g, "");
if (stripped) {
children.push(stripped);
}
const newlines = word.match(/\n/g);
if (newlines) {
children.push(hardline);

const endSpace = /\s+$/.test(line);
if (endSpace) {
children.push(softline);
children.push(jsxWhitespace);
// allow one extra newline
if (newlines.length > 1) {
children.push(hardline);
}
});

if (!isLineNext(util.getLast(children))) {
children.push(softline);
return;
}
} else if (/\n/.test(value)) {
children.push(hardline);

// allow one extra newline
if (value.match(/\n/g).length > 1) {
children.push(hardline);
const space = /^\s+$/.test(word);
if (space) {
// children.push(line);
return;
}
} else if (/\s/.test(value)) {
// whitespace-only without newlines,
// eg; a single space separating two elements
children.push(jsxWhitespace);
children.push(softline);
}

children.push(word);
});

} else {
children.push(print(childPath));

// add a line unless it's followed by a JSX newline
let next = n.children[i + 1];
if (!(next && /^\s*\n/.test(next.value))) {
children.push(softline);
}
// // add a line unless it's followed by a JSX newline
// let next = n.children[i + 1];
// if (!(next && /^\s*\n/.test(next.value))) {
// children.push(softline);
// }
}
}, "children");

Expand Down Expand Up @@ -3055,9 +3082,9 @@ function printJSXElement(path, options, print) {
concat(
groups.map(
contents =>
(Array.isArray(contents)
? conditionalGroup([concat(contents)])
: contents)
Array.isArray(contents)
? fill(contents)
: contents
)
)
];
Expand All @@ -3076,7 +3103,7 @@ function printJSXElement(path, options, print) {
}

return conditionalGroup([
group(concat([openingLines, concat(children), closingLines])),
group(concat([openingLines, fill(children), closingLines])),
multiLineElem
]);
}
Expand Down
14 changes: 4 additions & 10 deletions tests/arrows/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -200,29 +200,23 @@ function render() {
function render() {
return (
<View>
<Image
onProgress={e =>
this.setState({
<Image onProgress={e => this.setState({
progress: Math.round(
100 * e.nativeEvent.loaded / e.nativeEvent.total
)
})}
/>
})} />
</View>
);
}
function render() {
return (
<View>
<Image
onProgress={e =>
this.setState({
<Image onProgress={e => this.setState({
progress: Math.round(
100 * e.nativeEvent.loaded / e.nativeEvent.total
)
})}
/>
})} />
</View>
);
}
Expand Down
38 changes: 11 additions & 27 deletions tests/comments/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -489,9 +489,7 @@ Observable.of(process)
.takeUntil(exit);
// Comments disappear inside of JSX
<div>
{/* Some comment */}
</div>;
<div>{/* Some comment */}</div>;
// Comments in JSX tag are placed in a non optimal way
<div
Expand Down Expand Up @@ -590,39 +588,25 @@ exports[`jsx.js 1`] = `
<div>{/*<div> Some very v ery very very long line to break line width limit </div>*/}</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<div>
{/* comment */}
</div>;
<div>{/* comment */}</div>;
<div>
{/* comment */}
</div>;
<div>{/* comment */}</div>;
<div>
{/* comment
*/}
</div>;
<div>{/* comment
*/}</div>;
<div>
{a /* comment
*/}
</div>;
<div>{a /* comment
*/}</div>;
<div>
{
/* comment
{/* comment
*/
a
}
a}
</div>;
<div>
{/* comment */}
</div>;
<div>{/* comment */}</div>;
<div>
{/* comment */}
</div>;
<div>{/* comment */}</div>;
<div>
{
Expand Down

0 comments on commit ae09ade

Please sign in to comment.