From 58a1df115024788d43a19977768ebdaf43e752e2 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Sun, 5 Mar 2023 10:21:58 -0600 Subject: [PATCH] fix: handle line duplication bug with proper line wrapping --- .changeset/good-islands-provide.md | 6 ++++ packages/core/package.json | 3 ++ packages/core/src/prompts/prompt.ts | 8 +++-- pnpm-lock.yaml | 46 +++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 .changeset/good-islands-provide.md diff --git a/.changeset/good-islands-provide.md b/.changeset/good-islands-provide.md new file mode 100644 index 00000000..37423819 --- /dev/null +++ b/.changeset/good-islands-provide.md @@ -0,0 +1,6 @@ +--- +'@clack/core': patch +'@clack/prompts': patch +--- + +Fix line duplication bug by automatically wrapping prompts to `process.stdout.columns` diff --git a/packages/core/package.json b/packages/core/package.json index b648df72..ee914b00 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -55,5 +55,8 @@ "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" + }, + "devDependencies": { + "wrap-ansi": "^8.1.0" } } diff --git a/packages/core/src/prompts/prompt.ts b/packages/core/src/prompts/prompt.ts index 1efd83c5..9e461048 100644 --- a/packages/core/src/prompts/prompt.ts +++ b/packages/core/src/prompts/prompt.ts @@ -5,6 +5,7 @@ import readline from 'node:readline'; import { Readable, Writable } from 'node:stream'; import { WriteStream } from 'node:tty'; import { cursor, erase } from 'sisteransi'; +import wrap from 'wrap-ansi'; function diffLines(a: string, b: string) { if (a === b) return; @@ -104,17 +105,20 @@ export default class Prompt { this.input.on('keypress', this.onKeypress); setRawMode(this.input, true); + this.output.on('resize', this.render); this.render(); return new Promise((resolve, reject) => { this.once('submit', () => { this.output.write(cursor.show); + this.output.off('resize', this.render); setRawMode(this.input, false); resolve(this.value); }); this.once('cancel', () => { this.output.write(cursor.show); + this.output.off('resize', this.render); setRawMode(this.input, false); resolve(cancel); }); @@ -203,13 +207,13 @@ export default class Prompt { // TODO: handle wrapping private restoreCursor() { - const lines = this._prevFrame.split('\n').length - 1; + const lines = wrap(this._prevFrame, process.stdout.columns).split('\n').length - 1; this.output.write(cursor.move(-999, lines * -1)); } private _prevFrame = ''; private render() { - const frame = this._render(this) ?? ''; + const frame = wrap(this._render(this) ?? '', process.stdout.columns); if (frame === this._prevFrame) return; if (this.state === 'initial') { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef9f6189..cab14150 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,9 +50,12 @@ importers: specifiers: picocolors: ^1.0.0 sisteransi: ^1.0.5 + wrap-ansi: ^8.1.0 dependencies: picocolors: 1.0.0 sisteransi: 1.0.5 + devDependencies: + wrap-ansi: 8.1.0 packages/prompts: specifiers: @@ -903,6 +906,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex/6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + /ansi-styles/3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -917,6 +925,11 @@ packages: color-convert: 2.0.1 dev: true + /ansi-styles/6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -1203,6 +1216,10 @@ packages: path-type: 4.0.0 dev: true + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /editorconfig/0.15.3: resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} hasBin: true @@ -1221,6 +1238,10 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /enquirer/2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} @@ -2506,6 +2527,15 @@ packages: strip-ansi: 6.0.1 dev: true + /string-width/5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.0.1 + dev: true + /string.prototype.trimend/1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: @@ -2529,6 +2559,13 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-ansi/7.0.1: + resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + /strip-bom/3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -2804,6 +2841,15 @@ packages: strip-ansi: 6.0.1 dev: true + /wrap-ansi/8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.0.1 + dev: true + /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true