diff --git a/package.json b/package.json index 806e0e62..44f646ef 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "globby": "6.1.0", "graphql": "0.10.1", "ignore": "3.3.5", + "is-fullwidth-code-point": "2.0.0", "jest-docblock": "21.3.0-beta.1", "jest-validate": "21.1.0", "leven": "2.1.0", diff --git a/src/doc-printer.js b/src/doc-printer.js index 9910567d..41b2c4ef 100644 --- a/src/doc-printer.js +++ b/src/doc-printer.js @@ -1,5 +1,7 @@ "use strict"; +const isFullwidthCodePoint = require("is-fullwidth-code-point"); + const docBuilders = require("./doc-builders"); const concat = docBuilders.concat; const fill = docBuilders.fill; @@ -66,7 +68,7 @@ function fits(next, restCommands, width, mustBeFlat) { const doc = x[2]; if (typeof doc === "string") { - width -= doc.length; + width -= getStringWidth(doc); } else { switch (doc.type) { case "concat": @@ -153,7 +155,7 @@ function printDocToString(doc, options) { if (typeof doc === "string") { out.push(doc); - pos += doc.length; + pos += getStringWidth(doc); } else { switch (doc.type) { case "cursor": @@ -428,4 +430,15 @@ function printDocToString(doc, options) { return { formatted: out.join("") }; } +function getStringWidth(str) { + let width = 0; + + for (let i = 0; i < str.length; i++) { + const codePoint = str.codePointAt(i); + width += isFullwidthCodePoint(codePoint) ? 2 : 1; + } + + return width; +} + module.exports = { printDocToString }; diff --git a/tests_integration/__tests__/__snapshots__/cursor-offset.js.snap b/tests_integration/__tests__/__snapshots__/cursor-offset.js.snap index ec8eeb83..8a305b51 100644 --- a/tests_integration/__tests__/__snapshots__/cursor-offset.js.snap +++ b/tests_integration/__tests__/__snapshots__/cursor-offset.js.snap @@ -1,5 +1,24 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`cursorOffset should not be affected by full-width character (stdout) 1`] = ` +"const x = [ + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\", + \\"中文\\" +]; +" +`; + +exports[`cursorOffset should not be affected by full-width character (write) 1`] = `Array []`; + exports[`write cursorOffset to stderr with --cursor-offset (stderr) 1`] = ` "1 " diff --git a/tests_integration/__tests__/cursor-offset.js b/tests_integration/__tests__/cursor-offset.js index 011d6b87..d6e6cce2 100644 --- a/tests_integration/__tests__/cursor-offset.js +++ b/tests_integration/__tests__/cursor-offset.js @@ -7,3 +7,29 @@ describe("write cursorOffset to stderr with --cursor-offset ", () => { status: 0 }); }); + +describe("cursorOffset should not be affected by full-width character", () => { + runPrettier("cli", ["--cursor-offset", "21"], { + input: `const x = ["中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文"];` + // ^ offset = 21 ^ width = 80 + }).test({ + /** + * const x = [ + * "中文", + * "中文", + * ^ offset = 26 + * "中文", + * "中文", + * "中文", + * "中文", + * "中文", + * "中文", + * "中文", + * "中文", + * "中文" + * ]; + */ + stderr: "26\n", + status: 0 + }); +}); diff --git a/yarn.lock b/yarn.lock index f20aa1ed..1ddbd70d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2149,16 +2149,16 @@ is-finite@^1.0.0: dependencies: number-is-nan "^1.0.0" +is-fullwidth-code-point@2.0.0, is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"