« get me outta code hell

Add WrapLabel UI element - tui-lib - Pure Node.js library for making visual command-line programs (ala vim, ncdu)
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2018-06-12 23:55:06 -0300
committerFlorrie <towerofnix@gmail.com>2018-06-12 23:55:06 -0300
commitc5b3a076963517c93b6596f3e0a860be1d80ef80 (patch)
tree83bf575df2adb45227c39437d545a87347bad808
parent5ca7837f83be3c3ea1081db150ece49875fa61a0 (diff)
Add WrapLabel UI element
-rw-r--r--package-lock.json13
-rw-r--r--package.json3
-rw-r--r--ui/Label.js17
-rw-r--r--ui/WrapLabel.js44
4 files changed, 71 insertions, 6 deletions
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d020d44
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,13 @@
+{
+  "name": "tui-lib",
+  "version": "0.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "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 6c386f7..f92515b 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
   "author": "Florrie <towerofnix@gmail.com>",
   "license": "GPL-3.0",
   "dependencies": {
-    "iac": "^1.1.0"
+    "iac": "^1.1.0",
+    "word-wrap": "^1.2.3"
   }
 }
diff --git a/ui/Label.js b/ui/Label.js
index 850edc0..faeee98 100644
--- a/ui/Label.js
+++ b/ui/Label.js
@@ -5,20 +5,23 @@ const DisplayElement = require('./DisplayElement')
 module.exports = class Label extends DisplayElement {
   // A simple text display. Automatically adjusts size to fit text.
 
-  constructor(text='') {
+  constructor(text = '') {
     super()
 
     this.text = text
     this.textAttributes = []
   }
 
+  fixLayout() {
+    this.w = this.text.length
+  }
+
   drawTo(writable) {
     if (this.textAttributes.length) {
       writable.write(ansi.setAttributes(this.textAttributes))
     }
 
-    writable.write(ansi.moveCursor(this.absTop, this.absLeft))
-    writable.write(this.text)
+    this.writeTextTo(writable)
 
     if (this.textAttributes.length) {
       writable.write(ansi.resetAttributes())
@@ -27,10 +30,14 @@ module.exports = class Label extends DisplayElement {
     super.drawTo(writable)
   }
 
+  writeTextTo(writable) {
+    writable.write(ansi.moveCursor(this.absTop, this.absLeft))
+    writable.write(this.text)
+  }
+
   set text(newText) {
     this._text = newText
-
-    this.w = newText.length
+    this.fixLayout()
   }
 
   get text() {
diff --git a/ui/WrapLabel.js b/ui/WrapLabel.js
new file mode 100644
index 0000000..babf462
--- /dev/null
+++ b/ui/WrapLabel.js
@@ -0,0 +1,44 @@
+const ansi = require('../util/ansi')
+const wrap = require('word-wrap')
+
+const Label = require('./Label')
+
+module.exports = class WrapLabel extends Label {
+  // A word-wrapping text display. Given a width, wraps text to fit.
+
+  constructor(...args) {
+    super(...args)
+  }
+
+  fixLayout() {
+    // Override Label.fixLayout to do nothing. We don't want to make the
+    // width of this label be set to the content of the text! (That would
+    // defeat the entire point of word wrapping.)
+  }
+
+  writeTextTo(writable) {
+    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])
+    }
+  }
+
+  getWrappedLines() {
+    if (this.text.trim().length === 0) {
+      return []
+    }
+
+    const options = {width: this.w, indent: ''}
+    return wrap(this.text, options).split('\n')
+      .map(l => l.trim())
+  }
+
+  get h() {
+    return this.getWrappedLines().length
+  }
+
+  set h(newHeight) {
+    // Do nothing. Height is computed on the fly.
+  }
+}