From 78fa3344c00d48d935e4485c0b086fcfdccdea8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paula=20Santamar=C3=ADa?= Date: Mon, 22 Apr 2024 21:34:14 -0300 Subject: [PATCH] Allow client to get the current scroll position and an array with the split content (#6) * rename private fields with _ prefix * add getters * add tests for the new getters * improve jsdoc description --- src/scrollable.ts | 31 +++++++++++++----- tests/scrollable.test.ts | 70 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/src/scrollable.ts b/src/scrollable.ts index 5643542..db0d0ab 100644 --- a/src/scrollable.ts +++ b/src/scrollable.ts @@ -40,8 +40,8 @@ export type ScrollableOptions = { * A scrollable area that can be printed to the console. */ export class Scrollable { - private lines: string[] = []; - private currentLine = 0; + private _lines: string[] = []; + private _position = 0; private _options: ScrollableOptions; /** @@ -51,6 +51,21 @@ export class Scrollable { return this._options; } + /** + * The lines of content in the scrollable area + * wrapped according to the specified {@link ScrollableOptions} and split into an array of lines. + */ + get lines(): string[] { + return this._lines; + } + + /** + * The position of the first line to display in the scrollable area. + */ + get position(): number { + return this._position; + } + /** * Creates a new Scrollable instance. * @param options - The options for the Scrollable instance. @@ -130,7 +145,7 @@ export class Scrollable { * @returns The Scrollable instance. */ print(): this { - if (this.lines.length == 0) this.splitContentIntoLines(); + if (this._lines.length == 0) this.splitContentIntoLines(); const { x, y } = this._options.start; const { width, height } = this._options.size; const emptyLine = Array(width).fill(' ').join(''); @@ -141,7 +156,7 @@ export class Scrollable { stdout.cursorTo(x, y); for (let i = 0; i < height; i++) { - const line = this.lines[i + this.currentLine]; + const line = this._lines[i + this._position]; stdout.cursorTo(x); stdout.write((line ?? emptyLine) + '\n'); @@ -156,7 +171,7 @@ export class Scrollable { * @returns The Scrollable instance. */ scroll(lines: number): this { - this.currentLine += lines; + this._position += lines; return this; } @@ -180,8 +195,8 @@ export class Scrollable { } private resetLines(): void { - this.lines = []; - this.currentLine = 0; + this._lines = []; + this._position = 0; } private splitContentIntoLines(): void { @@ -192,6 +207,6 @@ export class Scrollable { this._options.size.width, this._options.wrapOptions ); - this.lines = wrapped.split('\n'); + this._lines = wrapped.split('\n'); } } diff --git a/tests/scrollable.test.ts b/tests/scrollable.test.ts index 555000e..bc34ddf 100644 --- a/tests/scrollable.test.ts +++ b/tests/scrollable.test.ts @@ -9,6 +9,70 @@ describe('Scrollable', () => { scrollable = new Scrollable({ stdout: createFakeStdout() }); }); + describe('get position', () => { + it('should return the current position of the scrollable area', () => { + scrollable.setContent( + 'Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod' + ); + + scrollable.scroll(1); + expect(scrollable.position).to.equal(1); + + scrollable.scroll(-2); + expect(scrollable.position).to.equal(-1); + + scrollable.scroll(5); + expect(scrollable.position).to.equal(4); + }); + }); + + describe('get lines', () => { + it('should return all the lines of the content in an array', () => { + scrollable + .setContent('Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod') + .setSize({ width: 12, height: 3 }) + .print(); + + expect(scrollable.lines).to.be.an('array').that.has.lengthOf(7); + expect(scrollable.lines[0]).to.equal('Lorem ipsum'); + expect(scrollable.lines[1]).to.equal('dolor sit'); + expect(scrollable.lines[2]).to.equal('amet'); + expect(scrollable.lines[3]).to.equal('consectetur'); + expect(scrollable.lines[4]).to.equal('adipiscing'); + expect(scrollable.lines[5]).to.equal('elit sed do'); + expect(scrollable.lines[6]).to.equal('eiusmod'); + }); + + it('should return all the lines of the content in an array considering newlines', () => { + scrollable + .setContent('Lorem \nipsum dolor sit\n amet consectetur') + .setSize({ width: 12, height: 3 }) + .print(); + + expect(scrollable.lines).to.be.an('array').that.has.lengthOf(5); + expect(scrollable.lines[0]).to.equal('Lorem'); + expect(scrollable.lines[1]).to.equal('ipsum dolor'); + expect(scrollable.lines[2]).to.equal('sit'); + expect(scrollable.lines[3]).to.equal('amet'); + expect(scrollable.lines[4]).to.equal('consectetur'); + }); + + it('should return all the lines of the content after scrolling', () => { + scrollable + .setContent('Lorem ipsum dolor sit amet consectetur') + .setSize({ width: 12, height: 3 }) + .print(); + + scrollable.scroll(4); + + expect(scrollable.lines).to.be.an('array').that.has.lengthOf(4); + expect(scrollable.lines[0]).to.equal('Lorem ipsum'); + expect(scrollable.lines[1]).to.equal('dolor sit'); + expect(scrollable.lines[2]).to.equal('amet'); + expect(scrollable.lines[3]).to.equal('consectetur'); + }); + }); + describe('print', () => { let spyWrite: SinonSpy; @@ -100,13 +164,13 @@ describe('Scrollable', () => { ); scrollable.scroll(1); - expect(scrollable['currentLine']).to.equal(1); + expect(scrollable['_position']).to.equal(1); scrollable.scroll(-2); - expect(scrollable['currentLine']).to.equal(-1); + expect(scrollable['_position']).to.equal(-1); scrollable.scroll(5); - expect(scrollable['currentLine']).to.equal(4); + expect(scrollable['_position']).to.equal(4); }); it('should print the correct lines after scrolling down', () => {