Skip to content
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

Add --range-start and --range-end options to format only parts of the input #1609

Merged
merged 21 commits into from
May 21, 2017
Merged
Show file tree
Hide file tree
Changes from 9 commits
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +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. 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
6 changes: 5 additions & 1 deletion bin/prettier.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const argv = minimist(process.argv.slice(2), {
// Deprecated in 0.0.10
"flow-parser"
],
string: ["print-width", "tab-width", "parser", "trailing-comma"],
string: ["print-width", "tab-width", "parser", "trailing-comma", "range-start", "range-end"],
default: { semi: true, color: true, "bracket-spacing": true, parser: "babylon" },
alias: { help: "h", version: "v", "list-different": "l" },
unknown: param => {
Expand Down Expand Up @@ -127,6 +127,8 @@ function getTrailingComma() {
}

const options = {
rangeStart: getIntOption("range-start"),
rangeEnd: getIntOption("range-end"),
useTabs: argv["use-tabs"],
semi: argv["semi"],
printWidth: getIntOption("print-width"),
Expand Down Expand Up @@ -217,6 +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. 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
33 changes: 31 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,45 @@ function ensureAllCommentsPrinted(astComments) {
});
}

function format(text, opts) {
function format(text, opts, addIndents) {
addIndents = 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);
// Remove extra leading newline as well as the added indentation after last newline
if (addIndents > 0) {
return str.slice(opts.newLine.length).trimRight() + opts.newLine;
}
return str;
}

function countIndents(text, opts) {
Copy link
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
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
2 changes: 2 additions & 0 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ var validate = require("jest-validate").validate;
var deprecatedConfig = require("./deprecated");

var defaults = {
rangeStart: 0,
rangeEnd: Infinity,
useTabs: false,
tabWidth: 2,
printWidth: 80,
Expand Down
32 changes: 25 additions & 7 deletions src/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,22 @@ function shouldPrintComma(options, level) {
}
}

function hasPrettierIgnoreComment(node) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need to extract it anymore right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, fixed in 1e60895

return (
node &&
node.comments &&
node.comments.length > 0 &&
node.comments.some(comment => comment.value.trim() === "prettier-ignore")
);
}

function genericPrint(path, options, printPath, args) {
assert.ok(path instanceof FastPath);

var node = path.getValue();

// Escape hatch
if (
node &&
node.comments &&
node.comments.length > 0 &&
node.comments.some(comment => comment.value.trim() === "prettier-ignore")
) {
if (hasPrettierIgnoreComment(node)) {
return options.originalText.slice(util.locStart(node), util.locEnd(node));
}

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

function printAstToDoc(ast, options) {
function printAstToDoc(ast, options, addIndents) {
addIndents = addIndents || 0;

function printGenerically(path, args) {
return comments.printComments(
path,
Expand All @@ -4256,7 +4262,19 @@ function printAstToDoc(ast, options) {

const doc = printGenerically(FastPath.from(ast));
docUtils.propagateBreaks(doc);
Copy link
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
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

if (addIndents > 0) {
// Add a hardline to make the indents take effect
// It should be removed in index.js format()
return addIndentsToDoc(concat([hardline, doc]), addIndents);
}
return doc;
}

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

module.exports = { printAstToDoc };
24 changes: 24 additions & 0 deletions tests/range/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`range.js 1`] = `
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
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
}
}
}

`;
1 change: 1 addition & 0 deletions tests/range/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
run_spec(__dirname, { rangeStart: 165, rangeEnd: 246 });
9 changes: 9 additions & 0 deletions tests/range/range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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
}
}
}