From 6489702a7e4143f8634f1d4854ff7d19d7456926 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 17 Oct 2019 12:31:55 -0300 Subject: Update package-lock.json Oops. --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 33f839f..84ec156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { -- cgit 1.3.0-6-gf8a5 From f1cc65d376141fa5e76878ffd3da4392f8a7c747 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 17 Oct 2019 12:32:13 -0300 Subject: Add .editorconfig --- .editorconfig | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5f27700 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true -- cgit 1.3.0-6-gf8a5 From 742d2543b88ad4cbb2fc9a859f093a57f32c1967 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 17 Oct 2019 12:57:24 -0300 Subject: Make ScrollBar an independent and published class It's no longer strictly connected to a ListScrollForm, and is published, so it's much easier to use as an element from the tui-lib API in any project now. --- index.js | 1 + ui/form/ListScrollForm.js | 115 +++---------------------------------------- ui/form/ScrollBar.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 108 deletions(-) create mode 100644 ui/form/ScrollBar.js diff --git a/index.js b/index.js index de4c680..b848814 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,7 @@ module.exports = { FocusElement: require('./ui/form/FocusElement'), Form: require('./ui/form/Form'), ListScrollForm: require('./ui/form/ListScrollForm'), + ScrollBar: require('./ui/form/ScrollBar'), TextInput: require('./ui/form/TextInput') } }, diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js index 78c376f..72e79df 100644 --- a/ui/form/ListScrollForm.js +++ b/ui/form/ListScrollForm.js @@ -1,9 +1,8 @@ const ansi = require('../../util/ansi') const telc = require('../../util/telchars') -const unic = require('../../util/unichars') -const DisplayElement = require('../DisplayElement') const Form = require('./Form') +const ScrollBar = require('./ScrollBar') module.exports = class ListScrollForm extends Form { // A form that lets the user scroll through a list of items. It @@ -21,7 +20,12 @@ module.exports = class ListScrollForm extends Form { this.scrollBarEnabled = enableScrollBar - this.scrollBar = new ScrollBar(this) + this.scrollBar = new ScrollBar({ + getLayoutType: () => this.layoutType, + getCurrentScroll: () => this.scrollItems, + getMaximumScroll: () => this.getScrollItemsLength(), + getTotalItems: () => this.inputs.length + }) this.scrollBarShown = false } @@ -297,108 +301,3 @@ module.exports = class ListScrollForm extends Form { } } } - -class ScrollBar extends DisplayElement { - constructor(listScrollForm) { - super() - - this.listScrollForm = listScrollForm - } - - fixLayout() { - // Normally we'd subtract one from contentW/contentH when setting the x/y - // position, but the scrollbar is actually displayed OUTSIDE of (adjacent - // to) the parent's content area. - if (this.listScrollForm.layoutType === 'vertical') { - this.h = this.listScrollForm.contentH - this.w = 1 - this.x = this.listScrollForm.contentW - this.y = 0 - } else { - this.h = 1 - this.w = this.listScrollForm.contentW - this.x = 0 - this.y = this.listScrollForm.contentH - } - } - - drawTo(writable) { - // Uuuurgh - this.fixLayout() - - // TODO: Horizontal layout! Not functionally a lot different, but I'm too - // lazy to write a test UI for it right now. - - const { - backwards: canScrollBackwards, - forwards: canScrollForwards - } = this.getScrollableDirections() - - // - 2 for extra UI elements (arrows) - const totalLength = this.h - 2 - - // ..[-----].. - // ^start| - // ^end - // - // Start and end should correspond to how much of the scroll area - // is currently visible. So, if you can see 60% of the full scroll length - // at a time, and you are scrolled 10% down, the start position of the - // handle should be 10% down, and it should extend 60% of the scrollbar - // length, to the 70% mark. - - const currentScroll = this.listScrollForm.scrollItems - const edgeLength = this.listScrollForm.contentH - const totalItems = this.listScrollForm.inputs.length - const itemsVisibleAtOnce = Math.min(totalItems, edgeLength) - const handleLength = itemsVisibleAtOnce / totalItems * totalLength - let handlePosition = Math.floor(totalLength / totalItems * currentScroll) - - // Silly peeve of mine: The handle should only be visibly touching the top - // or bottom of the scrollbar area if you're actually scrolled all the way - // to the start or end. Otherwise, it shouldn't be touching! There should - // visible space indicating that you can scroll in that direction - // (in addition to the arrows we show at the ends). - - if (canScrollBackwards && handlePosition === 0) { - handlePosition = 1 - } - - if (canScrollForwards && (handlePosition + handleLength) === edgeLength) { - handlePosition-- - } - - if (this.listScrollForm.layoutType === 'vertical') { - const start = this.absTop + handlePosition + 1 - for (let i = 0; i < handleLength; i++) { - writable.write(ansi.moveCursor(start + i, this.absLeft)) - writable.write(unic.BOX_V_DOUBLE) - } - - if (canScrollBackwards) { - writable.write(ansi.moveCursor(this.absTop, this.absLeft)) - writable.write(unic.ARROW_UP_DOUBLE) - } - - if (canScrollForwards) { - writable.write(ansi.moveCursor(this.absBottom, this.absLeft)) - writable.write(unic.ARROW_DOWN_DOUBLE) - } - } - } - - getScrollableDirections() { - const currentScroll = this.listScrollForm.scrollItems - const totalScroll = this.listScrollForm.getScrollItemsLength() - - return { - backwards: (currentScroll > 0), - forwards: (currentScroll < totalScroll) - } - } - - canScrollAtAll() { - const {backwards, forwards} = this.getScrollableDirections() - return backwards || forwards - } -} diff --git a/ui/form/ScrollBar.js b/ui/form/ScrollBar.js new file mode 100644 index 0000000..13ba7fe --- /dev/null +++ b/ui/form/ScrollBar.js @@ -0,0 +1,121 @@ +const DisplayElement = require('../DisplayElement') + +const ansi = require('../../util/ansi') +const unic = require('../../util/unichars') + +module.exports = class ScrollBar extends DisplayElement { + constructor({ + getLayoutType, + getCurrentScroll, + getMaximumScroll, + getTotalItems + }) { + super() + + this.getLayoutType = getLayoutType + this.getCurrentScroll = getCurrentScroll + this.getMaximumScroll = getMaximumScroll + this.getTotalItems = getTotalItems + } + + fixLayout() { + // Normally we'd subtract one from contentW/contentH when setting the x/y + // position, but the scroll-bar is actually displayed OUTSIDE of (adjacent + // to) the parent's content area. + if (this.getLayoutType() === 'vertical') { + this.h = this.parent.contentH + this.w = 1 + this.x = this.parent.contentW + this.y = 0 + } else { + this.h = 1 + this.w = this.parent.contentW + this.x = 0 + this.y = this.parent.contentH + } + } + + drawTo(writable) { + // Uuuurgh + this.fixLayout() + + // TODO: Horizontal layout! Not functionally a lot different, but I'm too + // lazy to write a test UI for it right now. + + const { + backwards: canScrollBackwards, + forwards: canScrollForwards + } = this.getScrollableDirections() + + // - 2 for extra UI elements (arrows) + const totalLength = this.h - 2 + + // ..[-----].. + // ^start| + // ^end + // + // Start and end should correspond to how much of the scroll area + // is currently visible. So, if you can see 60% of the full scroll length + // at a time, and you are scrolled 10% down, the start position of the + // handle should be 10% down, and it should extend 60% of the scrollbar + // length, to the 70% mark. + + // NB: I think this math mixes the units for "items" and "lines". + // edgeLength is measured in lines, while totalItems is a number of items. + // This isn't a problem when the length of an item is equal to one line, + // but it's still worth investigating at some point. + const currentScroll = this.getCurrentScroll() + const totalItems = this.getTotalItems() + const edgeLength = this.parent.contentH + const visibleAtOnce = Math.min(totalItems, edgeLength) + const handleLength = visibleAtOnce / totalItems * totalLength + let handlePosition = Math.floor(totalLength / totalItems * currentScroll) + + // Silly peeve of mine: The handle should only be visibly touching the top + // or bottom of the scrollbar area if you're actually scrolled all the way + // to the start or end. Otherwise, it shouldn't be touching! There should + // visible space indicating that you can scroll in that direction + // (in addition to the arrows we show at the ends). + + if (canScrollBackwards && handlePosition === 0) { + handlePosition = 1 + } + + if (canScrollForwards && (handlePosition + handleLength) === edgeLength) { + handlePosition-- + } + + if (this.getLayoutType() === 'vertical') { + const start = this.absTop + handlePosition + 1 + for (let i = 0; i < handleLength; i++) { + writable.write(ansi.moveCursor(start + i, this.absLeft)) + writable.write(unic.BOX_V_DOUBLE) + } + + if (canScrollBackwards) { + writable.write(ansi.moveCursor(this.absTop, this.absLeft)) + writable.write(unic.ARROW_UP_DOUBLE) + } + + if (canScrollForwards) { + writable.write(ansi.moveCursor(this.absBottom, this.absLeft)) + writable.write(unic.ARROW_DOWN_DOUBLE) + } + } + } + + getScrollableDirections() { + const currentScroll = this.getCurrentScroll() + const maximumScroll = this.getMaximumScroll() + + return { + backwards: (currentScroll > 0), + forwards: (currentScroll < maximumScroll) + } + } + + canScrollAtAll() { + const {backwards, forwards} = this.getScrollableDirections() + return backwards || forwards + } +} -- cgit 1.3.0-6-gf8a5 From 074a49b1f14739c42a38333756f94052d85d1a06 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 17 Oct 2019 13:04:16 -0300 Subject: NPM release - 0.1.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84ec156..964c85b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.0.4", + "version": "0.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1842a11..753963b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.0.4", + "version": "0.1.0", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", -- cgit 1.3.0-6-gf8a5 From 695149a96299f9f1d3d0cc0747a7390a82d69525 Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 23 Oct 2019 11:01:49 -0300 Subject: Correctly enable ANSI compression in tuiApp util --- util/tui-app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tui-app.js b/util/tui-app.js index a695e57..fe1cd03 100644 --- a/util/tui-app.js +++ b/util/tui-app.js @@ -14,7 +14,7 @@ module.exports = async function tuiApp(callback) { const flushable = new Flushable(process.stdout, true); - const root = new Root(interfacer); + const root = new Root(interfacer, flushable); const size = await interfacer.getScreenSize(); root.w = size.width; -- cgit 1.3.0-6-gf8a5 From a7f8734a33d1ffe549f83ea7186c56b831e933f0 Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 23 Oct 2019 11:02:38 -0300 Subject: NPM release - 0.1.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 964c85b..614b011 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.0.5", + "version": "0.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 753963b..33f58c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.1.0", + "version": "0.1.1", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", -- cgit 1.3.0-6-gf8a5 From 04a9e6f780bb05d855507d9092170d873e18e229 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 23 Apr 2020 16:17:58 -0300 Subject: add ListScrollForm.wheelMode --- package.json | 2 +- todo.txt | 4 ++++ ui/form/ListScrollForm.js | 38 +++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 todo.txt diff --git a/package.json b/package.json index 33f58c8..b2d3cb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.1.1", + "version": "0.2.1", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..6a0fffc --- /dev/null +++ b/todo.txt @@ -0,0 +1,4 @@ +TODO: Figure out why the text cursor is positioned differently when using + ANSI compression. + +TODO: Horizontal scroll-bars. diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js index 72e79df..e4f4249 100644 --- a/ui/form/ListScrollForm.js +++ b/ui/form/ListScrollForm.js @@ -15,6 +15,7 @@ module.exports = class ListScrollForm extends Form { super() this.layoutType = layoutType + this.wheelMode = 'scroll' // scroll, selection this.scrollItems = 0 @@ -122,27 +123,26 @@ module.exports = class ListScrollForm extends Form { } clicked(button) { - // Old code for changing the actual selected item...maybe an interesting - // functionality to explore later? - /* - if (button === 'scroll-up') { - this.previousInput() - this.scrollSelectedElementIntoView() - } else if (button === 'scroll-down') { - this.nextInput() - this.scrollSelectedElementIntoView() - } - */ - - // Scrolling is typically pretty slow with a mouse wheel when it's by - // a single line, so scroll at 3x that speed. - for (let i = 0; i < 3; i++) { + if (this.wheelMode === 'selection') { + // Change the actual selected item. if (button === 'scroll-up') { - this.scrollItems-- + this.previousInput() + this.scrollSelectedElementIntoView() } else if (button === 'scroll-down') { - this.scrollItems++ - } else { - return + this.nextInput() + this.scrollSelectedElementIntoView() + } + } else if (this.wheelMode === 'scroll') { + // Scrolling is typically pretty slow with a mouse wheel when it's by + // a single line, so scroll at 3x that speed. + for (let i = 0; i < 3; i++) { + if (button === 'scroll-up') { + this.scrollItems-- + } else if (button === 'scroll-down') { + this.scrollItems++ + } else { + return + } } } -- cgit 1.3.0-6-gf8a5 From be0919ac31b1048248941ed0c290c03824732297 Mon Sep 17 00:00:00 2001 From: Florrie Date: Sun, 3 May 2020 14:57:01 -0300 Subject: fix long-ignored crash interacting with empty form --- package-lock.json | 2 +- package.json | 2 +- ui/form/Form.js | 21 ++++++++++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 614b011..cb7226e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.1.1", + "version": "0.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b2d3cb2..a1d575d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.2.1", + "version": "0.2.2", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", diff --git a/ui/form/Form.js b/ui/form/Form.js index 451baa4..f61c7b6 100644 --- a/ui/form/Form.js +++ b/ui/form/Form.js @@ -81,8 +81,10 @@ module.exports = class Form extends FocusElement { } previousInput() { - // TODO: Forms currently assume there is at least one selectable input, - // but this isn't necessarily always the case. + if (this.inputs.length === 0) { + return + } + do { this.curIndex = (this.curIndex - 1) if (this.curIndex < 0) { @@ -94,7 +96,10 @@ module.exports = class Form extends FocusElement { } nextInput() { - // TODO: See previousInput + if (this.inputs.length === 0) { + return + } + do { this.curIndex = (this.curIndex + 1) % this.inputs.length } while (!this.inputs[this.curIndex].selectable) @@ -103,9 +108,12 @@ module.exports = class Form extends FocusElement { } firstInput(selectForm = true) { + if (this.inputs.length === 0) { + return + } + this.curIndex = 0 - // TODO: See previousInput if (!this.inputs[this.curIndex].selectable) { this.nextInput() } @@ -118,9 +126,12 @@ module.exports = class Form extends FocusElement { } lastInput(selectForm = true) { + if (this.inputs.length === 0) { + return + } + this.curIndex = this.inputs.length - 1 - // TODO: See previousInput if (!this.inputs[this.curIndex].selectable) { this.previousInput() } -- cgit 1.3.0-6-gf8a5 From 3bd328e68894a7819aa26e2325d7984eaa3959e0 Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 15 Jul 2020 22:08:34 -0300 Subject: don't include ANSI escape codes in measureColumns This allows pretty much any code based around measureColumns (e.g. buttons, labels, word-wrapping code) to handle ANSI-formatted text without any miscalculated measurements. --- package-lock.json | 2 +- package.json | 2 +- util/ansi.js | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb7226e..8530981 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.2.2", + "version": "0.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a1d575d..2f3f82f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.2.2", + "version": "0.2.3", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", diff --git a/util/ansi.js b/util/ansi.js index ac511ed..f921349 100644 --- a/util/ansi.js +++ b/util/ansi.js @@ -153,7 +153,12 @@ const ansi = { }, measureColumns(text) { - // Returns the number of columns the given text takes. + // Returns the number of columns the given text takes. Accounts for escape + // codes (by not including them in the returned width). + + if (text.includes(ESC)) { + text = text.replace(new RegExp(ESC + '\\[\\??[0-9]*.', 'g'), '') + } return wcwidth(text) }, -- cgit 1.3.0-6-gf8a5 From cff17d1f056a73714ff1ba5a735987d140a6b51c Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 16 Jul 2020 14:02:17 -0300 Subject: handle semicolons in measureColumns correctly too! --- util/ansi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/ansi.js b/util/ansi.js index f921349..d4ed71d 100644 --- a/util/ansi.js +++ b/util/ansi.js @@ -157,7 +157,7 @@ const ansi = { // codes (by not including them in the returned width). if (text.includes(ESC)) { - text = text.replace(new RegExp(ESC + '\\[\\??[0-9]*.', 'g'), '') + text = text.replace(new RegExp(ESC + '\\[\\??[0-9;]*.', 'g'), '') } return wcwidth(text) -- cgit 1.3.0-6-gf8a5 From 7f0579fc6e5771bbcad36591ab54119c4fe66dbd Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 16 Jul 2020 14:04:25 -0300 Subject: improve & use our own word wrapping code --- package-lock.json | 5 ----- package.json | 3 +-- ui/WrapLabel.js | 6 ++---- util/wrap.js | 8 +++++++- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8530981..3a51d91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,11 +24,6 @@ "requires": { "defaults": "^1.0.3" } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" } } } diff --git a/package.json b/package.json index 2f3f82f..4308565 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "author": "Florrie ", "license": "GPL-3.0", "dependencies": { - "wcwidth": "^1.0.1", - "word-wrap": "^1.2.3" + "wcwidth": "^1.0.1" } } diff --git a/ui/WrapLabel.js b/ui/WrapLabel.js index babf462..7036908 100644 --- a/ui/WrapLabel.js +++ b/ui/WrapLabel.js @@ -1,5 +1,5 @@ const ansi = require('../util/ansi') -const wrap = require('word-wrap') +const wrap = require('../util/wrap') const Label = require('./Label') @@ -29,9 +29,7 @@ module.exports = class WrapLabel extends Label { return [] } - const options = {width: this.w, indent: ''} - return wrap(this.text, options).split('\n') - .map(l => l.trim()) + return wrap(this.text, this.w).map(l => l.trim()) } get h() { diff --git a/util/wrap.js b/util/wrap.js index 3c381d4..71a1f1c 100644 --- a/util/wrap.js +++ b/util/wrap.js @@ -1,3 +1,5 @@ +const ansi = require('./ansi') + module.exports = function wrap(str, width) { // Wraps a string into separate lines. Returns an array of strings, for // each line of the text. @@ -6,13 +8,17 @@ module.exports = function wrap(str, width) { const words = str.split(' ') let curLine = words[0] + let curColumns = ansi.measureColumns(curLine) for (const word of words.slice(1)) { - if (curLine.length + word.length > width) { + const wordColumns = ansi.measureColumns(word) + if (curColumns + wordColumns > width) { lines.push(curLine) curLine = word + curColumns = wordColumns } else { curLine += ' ' + word + curColumns += 1 + wordColumns } } -- cgit 1.3.0-6-gf8a5 From 154dd2f631edc9f46ff73e80b54d48f0ccdf049a Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 16 Jul 2020 14:05:54 -0300 Subject: support mixed textAttributes & ANSI format labels --- ui/Label.js | 17 ++++++++++++++++- ui/WrapLabel.js | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ui/Label.js b/ui/Label.js index f2cd405..b5828cb 100644 --- a/ui/Label.js +++ b/ui/Label.js @@ -4,6 +4,16 @@ const DisplayElement = require('./DisplayElement') module.exports = class Label extends DisplayElement { // A simple text display. Automatically adjusts size to fit text. + // + // Supports formatted text in two ways: + // 1) Modify the textAttributes to be an array containing the ANSI numerical + // codes for any wanted attributes, and/or + // 2) Supply full ANSI escape codes within the text itself. (The reset + // attributes code, ESC[0m, will be processed to reset to the provided + // values in textAttributes. + // + // Subclasses overriding the writeTextTo function should be sure to call + // processFormatting before actually writing text. constructor(text = '') { super() @@ -32,7 +42,12 @@ module.exports = class Label extends DisplayElement { writeTextTo(writable) { writable.write(ansi.moveCursor(this.absTop, this.absLeft)) - writable.write(this.text) + writable.write(this.processFormatting(this.text)) + } + + processFormatting(text) { + return text.replace(new RegExp(ansi.ESC + '\\[0m', 'g'), + ansi.setAttributes([ansi.A_RESET, ...this.textAttributes])) } set text(newText) { diff --git a/ui/WrapLabel.js b/ui/WrapLabel.js index 7036908..d40b29d 100644 --- a/ui/WrapLabel.js +++ b/ui/WrapLabel.js @@ -20,7 +20,7 @@ module.exports = class WrapLabel extends Label { const lines = this.getWrappedLines() for (let i = 0; i < lines.length; i++) { writable.write(ansi.moveCursor(this.absTop + i, this.absLeft)) - writable.write(lines[i]) + writable.write(this.processFormatting(lines[i])) } } -- cgit 1.3.0-6-gf8a5 From 4b74578923e02a7a56a45c5bb7b505e95bbede08 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 16 Jul 2020 14:07:53 -0300 Subject: NPM release - 0.3.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a51d91..e2796f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.2.3", + "version": "0.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4308565..8d4a1d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.2.3", + "version": "0.3.0", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", -- cgit 1.3.0-6-gf8a5 From ef66a02f238bedccdefd2a5e60ee29c1325c51aa Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 16 Jul 2020 14:14:21 -0300 Subject: don't let WrapLabel text extend one letter too far I Am Very Good At Managing Npm Repositories --- package-lock.json | 2 +- package.json | 2 +- ui/WrapLabel.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2796f0..54eefb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8d4a1d3..3a10b24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.3.0", + "version": "0.3.1", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", diff --git a/ui/WrapLabel.js b/ui/WrapLabel.js index d40b29d..d621a49 100644 --- a/ui/WrapLabel.js +++ b/ui/WrapLabel.js @@ -29,7 +29,7 @@ module.exports = class WrapLabel extends Label { return [] } - return wrap(this.text, this.w).map(l => l.trim()) + return wrap(this.text, this.w - 1).map(l => l.trim()) } get h() { -- cgit 1.3.0-6-gf8a5 From 085bab481b1ee8470f04cb6541ee01981e19f2c6 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 14 Sep 2020 17:10:35 -0300 Subject: fix exception function not being imported properly --- ui/DisplayElement.js | 1 - ui/Element.js | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/DisplayElement.js b/ui/DisplayElement.js index 8720142..a7a371a 100644 --- a/ui/DisplayElement.js +++ b/ui/DisplayElement.js @@ -1,5 +1,4 @@ const Element = require('./Element') -const exception = require('../util/exception') module.exports = class DisplayElement extends Element { // A general class that handles dealing with screen coordinates, the tree diff --git a/ui/Element.js b/ui/Element.js index c5beb59..b9b8c61 100644 --- a/ui/Element.js +++ b/ui/Element.js @@ -1,4 +1,5 @@ const EventEmitter = require('events') +const exception = require('../util/exception') module.exports = class Element extends EventEmitter { // The basic class containing methods for working with an element hierarchy. -- cgit 1.3.0-6-gf8a5 From 691dee525adec2bbdb0bb247b6561bc2b5b23bf2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 14 Dec 2021 08:24:30 -0400 Subject: allow matching children of clickThrough: false els This caused clicks not to match the context menu in mtui, where the container layer (a full-screen element) is marked clickThrough: false (but the menu and its elements are not). Basically this meant clicking menus has been broken for however long this code has been here. --- ui/DisplayElement.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/DisplayElement.js b/ui/DisplayElement.js index a7a371a..32a62b8 100644 --- a/ui/DisplayElement.js +++ b/ui/DisplayElement.js @@ -233,7 +233,7 @@ module.exports = class DisplayElement extends Element { children.reverse() for (const el of children) { - if (!el.visible || el.clickThrough) { + if (!el.visible) { continue } @@ -242,6 +242,10 @@ module.exports = class DisplayElement extends Element { return el2 } + if (el.clickThrough) { + continue + } + const { absX, absY, w, h } = el if (absX <= x && absX + w > x) { if (absY <= y && absY + h > y) { -- cgit 1.3.0-6-gf8a5 From a90b90044fa6000bf0fa3490c20b6bf5c6502b1d Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 14 Dec 2021 08:30:24 -0400 Subject: NPM release - 0.3.2 --- package-lock.json | 37 +++++++++++++++++++++++++++++++++++-- package.json | 2 +- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54eefb0..49b072a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,41 @@ { "name": "tui-lib", - "version": "0.3.1", - "lockfileVersion": 1, + "version": "0.3.2", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "version": "0.3.2", + "license": "GPL-3.0", + "dependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dependencies": { + "defaults": "^1.0.3" + } + } + }, "dependencies": { "clone": { "version": "1.0.4", diff --git a/package.json b/package.json index 3a10b24..9ee045d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.3.1", + "version": "0.3.2", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", -- cgit 1.3.0-6-gf8a5 From 3614ce99f2eaa910a2b11b0f2f4a8a291ee3a4b0 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 25 Mar 2022 17:39:41 -0300 Subject: fix ancient waitForData util listener memory leak Particularly, this added a new event listener (i.e. function) every time the screen was resized, which would never be garbage collected. Oops. --- util/waitForData.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/waitForData.js b/util/waitForData.js index bf40c52..ed88402 100644 --- a/util/waitForData.js +++ b/util/waitForData.js @@ -1,9 +1,11 @@ module.exports = function waitForData(stream, cond = null) { return new Promise(resolve => { - stream.on('data', data => { + const listener = data => { if (cond ? cond(data) : true) { resolve(data) + stream.removeListener('data', listener) } - }) + } + stream.on('data', listener) }) } -- cgit 1.3.0-6-gf8a5 From a37d6be77261b2aae25c4235dcb38dd7b1bb60b1 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 25 Mar 2022 17:41:12 -0300 Subject: NPM release - 0.3.3 --- package-lock.json | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49b072a..e62e5f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "tui-lib", - "version": "0.3.2", + "version": "0.3.3", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.3.2", + "name": "tui-lib", + "version": "0.3.3", "license": "GPL-3.0", "dependencies": { "wcwidth": "^1.0.1" diff --git a/package.json b/package.json index 9ee045d..f07f4d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tui-lib", - "version": "0.3.2", + "version": "0.3.3", "description": "terminal ui library", "main": "index.js", "repository": "https://notabug.org/towerofnix/tui-lib.git", -- cgit 1.3.0-6-gf8a5