Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
62bf068
printer: Extract hasPrettierIgnoreComment() helper
josephfrazier May 14, 2017
5c97525
Add `--range-start` and `--range-end` options to format only parts of…
josephfrazier May 14, 2017
564bf13
Move isOutsideRange() to util
josephfrazier May 15, 2017
c09e19e
Don't throw errors about comments outside range "not printing"
josephfrazier May 15, 2017
3af3f01
Remove unnecessary check from isOutsideRange()
josephfrazier May 15, 2017
8c99117
Make --range-end exclusive
josephfrazier May 15, 2017
44bfd9b
Change range formatting approach
josephfrazier May 15, 2017
91372be
Don't use default function parameters
josephfrazier May 15, 2017
c1a61eb
Hackily fix indentation of range formatting
josephfrazier May 15, 2017
1e60895
Revert "printer: Extract hasPrettierIgnoreComment() helper"
josephfrazier May 16, 2017
2ca9f18
Test automatically using the beginning of the rangeStart line and sam…
josephfrazier May 16, 2017
bec69d0
Fix automatically using the beginning of the rangeStart line and same…
josephfrazier May 16, 2017
070b941
Propagate breaks after adding an indentation-triggering hardline
josephfrazier May 16, 2017
e1c993e
Extract getAlignmentSize(), use instead of countIndents()
josephfrazier May 16, 2017
77a8fb0
Extract addAlignmentToDoc(), use instead of addIndentsToDoc()
josephfrazier May 16, 2017
ef3b992
Document that --range-start and --range-end include the entire line
josephfrazier May 16, 2017
ee94a37
Fix rangeStart calculation
josephfrazier May 16, 2017
7823f75
Merge branch 'master' into range
josephfrazier May 20, 2017
990a18c
Extract formatRange() helper function
josephfrazier May 20, 2017
db0ec7a
Move getAlignmentSize() from printer to util
josephfrazier May 21, 2017
149e18c
Move addAlignmentToDoc() from printer to doc-builders
josephfrazier May 21, 2017
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
Prev Previous commit
Next Next commit
Change range formatting approach
NOTE: This doesn't pass its test yet. Note that since we're reading the
indentation from the first line, it is expected not to change. However,
a semicolon is added, and the lines outside the range are not changed.

The new approach is roughly:

* Require that the range exactly covers an integer number of lines of the input
* Detect the indentation of the line the range starts on
* Format the range's substring using `printAstToDoc`
* Add enough `indent`s to the doc to restore the detected indentation
* Format the doc to a string with `printDocToString`
* Prepend/append the original input before/after the range

See #1609 (comment)

---

Given `tests/range/range.js`, run the following:

    prettier tests/range/range.js --range-start 165 --range-end 246

See the range's text with:

    dd if=tests/range/range.js ibs=1 skip=165 count=81 2>/dev/null
  • Loading branch information
josephfrazier committed May 15, 2017
commit 44bfd9b0d72911f177075a2108153a8681ab1cb4
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ Prettier ships with a handful of customizable format options, usable in both the
| **JSX Brackets on Same Line** - Put the `>` of a multi-line JSX element at the end of the last line instead of being alone on the next line | `false` | `--jsx-bracket-same-line` | `jsxBracketSameLine: <bool>` |
| **Parser** - Specify which parser to use. | `babylon` | <code>--parser <flow&#124;babylon></code> | <code>parser: "<flow&#124;babylon>"</code> |
| **Semicolons** - Print semicolons at the ends of statements.<br /><br />Valid options: <br /> - `true` - add a semicolon at the end of every statement <br /> - `false` - only add semicolons at the beginning of lines that may introduce ASI failures | `true` | `--no-semi` | `semi: <bool>` |
| **Range Start** - Format code starting at a given character offset. | `0` | `--range-start <int>` | `rangeStart: <int>` |
| **Range End** - Format code ending at a given character offset (exclusive). | `Infinity` | `--range-end <int>` | `rangeEnd: <int>` |
| **Range Start** - Format code starting at a given character offset. The range must begin immediately before the start of a line. | `0` | `--range-start <int>` | `rangeStart: <int>` |
| **Range End** - Format code ending at a given character offset (exclusive). The range must end immediately after the end of a line. | `Infinity` | `--range-end <int>` | `rangeEnd: <int>` |

### Excluding code from formatting

Expand Down
4 changes: 2 additions & 2 deletions bin/prettier.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ if (argv["help"] || (!filepatterns.length && !stdin)) {
" --trailing-comma <none|es5|all>\n" +
" Print trailing commas wherever possible. Defaults to none.\n" +
" --parser <flow|babylon> Specify which parse to use. Defaults to babylon.\n" +
" --range-start <int> Format code starting at a given character offset. Defaults to 0.\n" +
" --range-end <int> Format code ending at a given character offset (exclusive). Defaults to Infinity.\n" +
" --range-start <int> Format code starting at a given character offset. Must be at the start of a line. Defaults to 0.\n" +
" --range-end <int> Format code ending at a given character offset (exclusive). Must be at the end of a line. Defaults to Infinity.\n" +
" --no-color Do not colorize error messages.\n" +
" --version or -v Print Prettier version.\n" +
"\n"
Expand Down
41 changes: 32 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use strict";

const comments = require("./src/comments");
const util = require('./src/util');
const version = require("./package.json").version;
const printAstToDoc = require("./src/printer").printAstToDoc;
const printDocToString = require("./src/doc-printer").printDocToString;
Expand All @@ -28,7 +27,7 @@ function attachComments(text, ast, opts) {
return astComments;
}

function ensureAllCommentsPrinted(astComments, opts) {
function ensureAllCommentsPrinted(astComments) {
for (let i = 0; i < astComments.length; ++i) {
if (astComments[i].value.trim() === "prettier-ignore") {
// If there's a prettier-ignore, we're not printing that sub-tree so we
Expand All @@ -38,10 +37,7 @@ function ensureAllCommentsPrinted(astComments, opts) {
}

astComments.forEach(comment => {
if (
!comment.printed &&
!util.isOutsideRange(comment, opts.rangeStart, opts.rangeEnd)
) {
if (!comment.printed) {
throw new Error(
'Comment "' +
comment.value.trim() +
Expand All @@ -52,16 +48,43 @@ function ensureAllCommentsPrinted(astComments, opts) {
});
}

function format(text, opts) {
function format(text, opts, addIndents = 0) {
const rangeStart = opts.rangeStart;
const rangeEnd = Math.min(opts.rangeEnd, text.length)

if (0 < rangeStart || rangeEnd < text.length) {
const rangeString = text.substring(rangeStart, rangeEnd)
const numIndents = countIndents(rangeString, opts);

const rangeFormatted = format(rangeString, Object.assign({}, opts, {
rangeStart: 0,
rangeEnd: Infinity,
printWidth: opts.printWidth - numIndents * opts.tabWidth
}), numIndents);

return text.slice(0, rangeStart) + rangeFormatted + text.slice(rangeEnd)
}

const ast = parser.parse(text, opts);
const astComments = attachComments(text, ast, opts);
const doc = printAstToDoc(ast, opts);
const doc = printAstToDoc(ast, opts, addIndents)
opts.newLine = guessLineEnding(text);
const str = printDocToString(doc, opts);
ensureAllCommentsPrinted(astComments, opts);
ensureAllCommentsPrinted(astComments);
// Remove added indentation after last newline
if (addIndents > 0) {
return str.trimRight() + opts.newLine;
}
return str;
}

function countIndents(text, opts) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you look at template literal code, I have some piece of code that is much more precise.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ooh, that is quite a lot better! Fixed in e1c993e and 77a8fb0

const tabSpaces = ' '.repeat(opts.tabWidth);
const indentation = text.match(/^([ \t]*)/)[1].replace(/\t/g, tabSpaces);
const numIndents = Math.floor(indentation.length / opts.tabWidth);
return numIndents;
}

function formatWithShebang(text, opts) {
if (!text.startsWith("#!")) {
return format(text, opts);
Expand Down
16 changes: 10 additions & 6 deletions src/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ function genericPrint(path, options, printPath, args) {
var node = path.getValue();

// Escape hatch
if (
hasPrettierIgnoreComment(node) ||
util.isOutsideRange(node, options.rangeStart, options.rangeEnd)
) {
if (hasPrettierIgnoreComment(node)) {
return options.originalText.slice(util.locStart(node), util.locEnd(node));
}

Expand Down Expand Up @@ -4251,7 +4248,7 @@ function removeLines(doc) {
});
}

function printAstToDoc(ast, options) {
function printAstToDoc(ast, options, addIndents = 0) {
function printGenerically(path, args) {
return comments.printComments(
path,
Expand All @@ -4263,7 +4260,14 @@ function printAstToDoc(ast, options) {

const doc = printGenerically(FastPath.from(ast));
docUtils.propagateBreaks(doc);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should likely be done after you add hardline as hardline intro a break. This isn't going to do anything wrong here but it would be better to do the "right" thing as if we're adding some more code that relies on this, it's going to break in unexpected ways.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh, I hadn't considered that (I didn't really think about what propagateBreaks does). Fixed in 070b941

return doc;
return addIndentsToDoc(doc, addIndents);
}

function addIndentsToDoc(doc, numIndents) {
if (numIndents <= 0) {
return doc;
}
return addIndentsToDoc(indent(doc), numIndents - 1);
}

module.exports = { printAstToDoc };
13 changes: 1 addition & 12 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,16 +320,6 @@ function isBlockComment(comment) {
return comment.type === "Block" || comment.type === "CommentBlock";
}

function isOutsideRange(node, rangeStart, rangeEnd) {
if (!node) {
return false;
}
const nodeStart = locStart(node);
const nodeEnd = locEnd(node);
const isOutside = nodeEnd < rangeStart || nodeStart >= rangeEnd;
return isOutside;
}

module.exports = {
getPrecedence,
isExportDeclaration,
Expand All @@ -351,6 +341,5 @@ module.exports = {
setLocEnd,
startsWithNoLookaheadToken,
hasBlockComments,
isBlockComment,
isOutsideRange
isBlockComment
};
44 changes: 16 additions & 28 deletions tests/range/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`range.js 1`] = `
// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

}

// will be formatted
function ugly ( has , unPrettier , param,spacing) {
\`multiline template string
with too much indentation\`
}

// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
\`multiline template string
with too much indentation\`
// The [165, 246) range selects the above two lines, including the second newline
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

}

// will be formatted
function ugly(has, unPrettier, param, spacing) {
\`multiline template string
with too much indentation\`;
}

// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
\`multiline template string
with too much indentation\`;
// The [165, 246) range selects the above two lines, including the second newline
}
}
}

`;
2 changes: 1 addition & 1 deletion tests/range/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, { rangeStart: 103, rangeEnd: 159 });
run_spec(__dirname, { rangeStart: 165, rangeEnd: 246 });
22 changes: 8 additions & 14 deletions tests/range/range.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

}

// will be formatted
function ugly ( has , unPrettier , param,spacing) {
`multiline template string
with too much indentation`
}

// will NOT be formatted
function ugly ( has , unPrettier , param,spacing) {

function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
function ugly ( {a=1, b = 2 } ) {
`multiline template string
with too much indentation`
// The [165, 246) range selects the above two lines, including the second newline
}
}
}