From 5dc3e663d8fadcf03c966c23d5fdf966f96a1b7d Mon Sep 17 00:00:00 2001 From: Nekrasov Pavel Date: Fri, 27 Sep 2024 15:31:11 +0200 Subject: [PATCH 1/8] Update textarea.js Added basic cursor movement --- lib/widgets/textarea.js | 77 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index dc94609c..d848a9c9 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -34,6 +34,9 @@ function Textarea(options) { this.screen._listenKeys(this); + this.offsetY = 0; + this.offsetX = 0; + this.value = options.value || ''; this.__updateCursor = this._updateCursor.bind(this); @@ -69,15 +72,44 @@ Textarea.prototype.__proto__ = Input.prototype; Textarea.prototype.type = 'textarea'; +Textarea.prototype.getCursor = function(){ + return {x: this.offsetX, y: this.offsetY}; +} + +Textarea.prototype.moveCursor = function(x, y){ + var prevLine = (this._clines.length - 1) + this.offsetY; + let sync = false; + if (y <= 0 && y > (this._clines.length * -1)){ + sync = this.offsetY !== y; + this.offsetY = y; + } + var currentLine = (this._clines.length - 1) + this.offsetY; + var currentText = this._clines[currentLine]; + + if (sync){ + var prevText = this._clines[prevLine]; + var positionFromBegin = this.strWidth(prevText) + this.offsetX; + x = (Math.max(0, this.strWidth(currentText) - positionFromBegin)) * -1; + } + if (x <= 0 && x >= (this.strWidth(currentText) * -1)){ + this.offsetX = x; + } + this._updateCursor(true); + + this.screen.render(); +} + Textarea.prototype._updateCursor = function(get) { if (this.screen.focused !== this) { return; } var lpos = get ? this.lpos : this._getCoords(); + if (!lpos) return; - var last = this._clines[this._clines.length - 1] + const currentLine = (this._clines.length - 1) + this.offsetY + var currentText = this._clines[currentLine] , program = this.screen.program , line , cx @@ -87,12 +119,12 @@ Textarea.prototype._updateCursor = function(get) { // and the last cline appears to always be empty from the // _typeScroll `+ '\n'` thing. // Maybe not necessary anymore? - if (last === '' && this.value[this.value.length - 1] !== '\n') { - last = this._clines[this._clines.length - 2] || ''; + if (currentText === '' && this.value[this.value.length - 1] !== '\n') { + currentText = this._clines[currentLine - 1] || ''; } line = Math.min( - this._clines.length - 1 - (this.childBase || 0), + currentLine - (this.childBase || 0), (lpos.yl - lpos.yi) - this.iheight - 1); // When calling clearValue() on a full textarea with a border, the first @@ -101,7 +133,7 @@ Textarea.prototype._updateCursor = function(get) { line = Math.max(0, line); cy = lpos.yi + this.itop + line; - cx = lpos.xi + this.ileft + this.strWidth(last); + cx = this.offsetX + lpos.xi + this.ileft + this.strWidth(currentText); // XXX Not sure, but this may still sometimes // cause problems when leaving editor. @@ -218,7 +250,20 @@ Textarea.prototype._listener = function(ch, key) { // TODO: Handle directional keys. if (key.name === 'left' || key.name === 'right' || key.name === 'up' || key.name === 'down') { - ; + var cursor = this.getCursor(); + + if (key.name === "left") { + cursor.x--; + } else if (key.name === "right") { + cursor.x++; + } + if (key.name === "up") { + cursor.y--; + } else if (key.name === "down") { + cursor.y++; + } + + this.moveCursor(cursor.x, cursor.y); } if (this.options.keys && key.ctrl && key.name === 'e') { @@ -239,12 +284,28 @@ Textarea.prototype._listener = function(ch, key) { this.value = this.value.slice(0, -1); } } else { - this.value = this.value.slice(0, -1); + if (this.offsetX === 0 && this.offsetY === 0){ + this.value = this.value.slice(0, -1); + } else if (this.offsetX > (this.value.length * -1)) { + const currentLine = (this._clines.length - 1) + this.offsetY + const copy = this._clines.slice(); + const cursorPosition = copy[currentLine].length + this.offsetX; + copy[currentLine] = copy[currentLine].slice(0, cursorPosition - 1) + copy[currentLine].slice(cursorPosition); + this.value = copy.join('\n'); + } } } } else if (ch) { if (!/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(ch)) { - this.value += ch; + if (this.offsetX === 0 && this.offsetY === 0){ + this.value += ch; + } else if (this.offsetX >= (this.value.length * -1)) { + const currentLine = (this._clines.length - 1) + this.offsetY + const copy = this._clines.slice(); + const cursorPosition = copy[currentLine].length + this.offsetX; + copy[currentLine] = copy[currentLine].slice(0, cursorPosition) + ch + copy[currentLine].slice(cursorPosition); + this.value = copy.join('\n'); + } } } From c41f000a264b253155e510a65da8506d1a2aff8e Mon Sep 17 00:00:00 2001 From: Nekrasov Pavel Date: Fri, 27 Sep 2024 15:53:50 +0200 Subject: [PATCH 2/8] Update textarea.js Fixed scroll position if type text with scroll bar --- lib/widgets/textarea.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index d848a9c9..0c3245a0 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -318,7 +318,8 @@ Textarea.prototype._typeScroll = function() { // XXX Workaround var height = this.height - this.iheight; if (this._clines.length - this.childBase > height) { - this.scroll(this._clines.length); + const currentLine = (this._clines.length) + this.offsetY + this.scroll(currentLine); } }; From 8e3a2a34912c0251310b69c5ac20b8cbd21dc6fc Mon Sep 17 00:00:00 2001 From: Nekrasov Pavel Date: Mon, 30 Sep 2024 14:43:56 +0200 Subject: [PATCH 3/8] Scroll hotfix (#2) * Update textarea.js * Update textarea.js variables reorder * Update textarea.js style --- lib/widgets/textarea.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index 0c3245a0..60227d0e 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -36,7 +36,7 @@ function Textarea(options) { this.offsetY = 0; this.offsetX = 0; - + this.value = options.value || ''; this.__updateCursor = this._updateCursor.bind(this); @@ -120,7 +120,7 @@ Textarea.prototype._updateCursor = function(get) { // _typeScroll `+ '\n'` thing. // Maybe not necessary anymore? if (currentText === '' && this.value[this.value.length - 1] !== '\n') { - currentText = this._clines[currentLine - 1] || ''; + //currentText = this._clines[currentLine - 1] || ''; } line = Math.min( @@ -290,7 +290,11 @@ Textarea.prototype._listener = function(ch, key) { const currentLine = (this._clines.length - 1) + this.offsetY const copy = this._clines.slice(); const cursorPosition = copy[currentLine].length + this.offsetX; - copy[currentLine] = copy[currentLine].slice(0, cursorPosition - 1) + copy[currentLine].slice(cursorPosition); + if (copy[currentLine] === ''){ + copy.splice(currentLine, 1); + }else{ + copy[currentLine] = copy[currentLine].slice(0, cursorPosition - 1) + copy[currentLine].slice(cursorPosition); + } this.value = copy.join('\n'); } } @@ -318,8 +322,8 @@ Textarea.prototype._typeScroll = function() { // XXX Workaround var height = this.height - this.iheight; if (this._clines.length - this.childBase > height) { - const currentLine = (this._clines.length) + this.offsetY - this.scroll(currentLine); + const currentLine = (this._clines.length - 1) + this.offsetY; + this.setScroll(currentLine); } }; From 9fd27fc81636ff8fecb94236cd04d61bd9df2ffb Mon Sep 17 00:00:00 2001 From: Nekrasov Pavel Date: Mon, 30 Sep 2024 16:51:06 +0200 Subject: [PATCH 4/8] Update textarea.js (#3) Fix for some corner cases --- lib/widgets/textarea.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index 60227d0e..2608159f 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -292,7 +292,12 @@ Textarea.prototype._listener = function(ch, key) { const cursorPosition = copy[currentLine].length + this.offsetX; if (copy[currentLine] === ''){ copy.splice(currentLine, 1); - }else{ + } else if (cursorPosition === 0) { + if (currentLine > 0){ + const currentLineString = copy.splice(currentLine, 1); + copy[currentLine - 1] += currentLineString; + } + } else { copy[currentLine] = copy[currentLine].slice(0, cursorPosition - 1) + copy[currentLine].slice(cursorPosition); } this.value = copy.join('\n'); From 3740961d1e9a4471574c22023f732f2f295e2acb Mon Sep 17 00:00:00 2001 From: Pavel Nekrasov Date: Fri, 11 Oct 2024 22:47:27 +0200 Subject: [PATCH 5/8] fix typing at the begining of multilines --- lib/widgets/textarea.js | 24 +++++++++++++++++++----- package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index 2608159f..4533af5b 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -88,7 +88,7 @@ Textarea.prototype.moveCursor = function(x, y){ if (sync){ var prevText = this._clines[prevLine]; - var positionFromBegin = this.strWidth(prevText) + this.offsetX; + var positionFromBegin = Math.max(this.strWidth(prevText) + this.offsetX, 0); x = (Math.max(0, this.strWidth(currentText) - positionFromBegin)) * -1; } if (x <= 0 && x >= (this.strWidth(currentText) * -1)){ @@ -312,7 +312,21 @@ Textarea.prototype._listener = function(ch, key) { const currentLine = (this._clines.length - 1) + this.offsetY const copy = this._clines.slice(); const cursorPosition = copy[currentLine].length + this.offsetX; - copy[currentLine] = copy[currentLine].slice(0, cursorPosition) + ch + copy[currentLine].slice(cursorPosition); + const maxCharacters = this.width - this.iwidth - 1; + for (let i = currentLine; i < copy.length; i++){ + let value = currentLine == i ? copy[i].slice(0, cursorPosition) + ch + copy[i].slice(cursorPosition) : copy[i]; + if (this.strWidth(value) >= maxCharacters){ + const newPart = value.slice(-1) + copy[i] = value.slice(0, -1) + if (copy[i + 1] === undefined){ + this.offsetY--; + } + copy[i + 1] = newPart + (copy[i + 1] ?? ""); + }else{ + copy[i] = value; + } + } + this.value = copy.join('\n'); } } @@ -325,11 +339,11 @@ Textarea.prototype._listener = function(ch, key) { Textarea.prototype._typeScroll = function() { // XXX Workaround - var height = this.height - this.iheight; - if (this._clines.length - this.childBase > height) { + //var height = this.height - this.iheight; + //if (this._clines.length - this.childBase > height) { const currentLine = (this._clines.length - 1) + this.offsetY; this.setScroll(currentLine); - } + //} }; Textarea.prototype.getValue = function() { diff --git a/package.json b/package.json index 7e923b39..31c5c453 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "blessed", - "description": "A high-level terminal interface library for node.js.", + "name": "semi-blessed", + "description": "A fork of BLESSED library with extra features.", "author": "Christopher Jeffrey", - "version": "0.1.81", + "version": "1.0.2", "license": "MIT", "main": "./lib/blessed.js", "bin": "./bin/tput.js", "preferGlobal": false, - "repository": "git://github.com/chjj/blessed.git", - "homepage": "https://github.com/chjj/blessed", - "bugs": { "url": "http://github.com/chjj/blessed/issues" }, + "repository": "git://github.com/freeart/blessed.git", + "homepage": "https://github.com/freeart/blessed", + "bugs": { "url": "http://github.com/freeart/blessed/issues" }, "keywords": ["curses", "tui", "tput", "terminfo", "termcap"], "tags": ["curses", "tui", "tput", "terminfo", "termcap"], "engines": { From f01c564d8c33f29c12f9d0c9f0e2ef07906727bf Mon Sep 17 00:00:00 2001 From: Pavel Nekrasov Date: Mon, 14 Oct 2024 11:47:32 +0200 Subject: [PATCH 6/8] support delete key --- lib/widgets/textarea.js | 44 +++++++++++++++++++++++++++++++++++++---- package.json | 2 +- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index 4533af5b..b938ba2b 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -277,19 +277,19 @@ Textarea.prototype._listener = function(ch, key) { } else if (key.name === 'backspace') { if (this.value.length) { if (this.screen.fullUnicode) { - if (unicode.isSurrogate(this.value, this.value.length - 2)) { + /*if (unicode.isSurrogate(this.value, this.value.length - 2)) { // || unicode.isCombining(this.value, this.value.length - 1)) { this.value = this.value.slice(0, -2); } else { this.value = this.value.slice(0, -1); - } + }*/ } else { if (this.offsetX === 0 && this.offsetY === 0){ this.value = this.value.slice(0, -1); - } else if (this.offsetX > (this.value.length * -1)) { + } else { const currentLine = (this._clines.length - 1) + this.offsetY const copy = this._clines.slice(); - const cursorPosition = copy[currentLine].length + this.offsetX; + const cursorPosition = this.strWidth(copy[currentLine]) + this.offsetX; if (copy[currentLine] === ''){ copy.splice(currentLine, 1); } else if (cursorPosition === 0) { @@ -304,6 +304,42 @@ Textarea.prototype._listener = function(ch, key) { } } } + } else if (key.name === 'delete') { + if (this.value.length) { + if (this.screen.fullUnicode) { + /*if (unicode.isSurrogate(this.value, this.value.length - 2)) { + // || unicode.isCombining(this.value, this.value.length - 1)) { + this.value = this.value.slice(0, -2); + } else { + this.value = this.value.slice(0, -1); + }*/ + } else { + const currentLine = (this._clines.length - 1) + this.offsetY + if (this.offsetX === 0 && this.offsetY === 0){ + //this.value = this.value.slice(1); + } else { + const copy = this._clines.slice(); + const cursorPosition = this.strWidth(copy[currentLine]) + this.offsetX; + if (copy[currentLine] === ''){ + const nextLineLength = this.strWidth(copy[currentLine + 1] ?? '') + copy.splice(currentLine, 1); + this.offsetY++; + this.offsetX = -nextLineLength; + } else if (cursorPosition === this.strWidth(copy[currentLine])) { + if (currentLine < copy.length - 1){ + this.offsetY++; + this.offsetX = -this.strWidth(copy[currentLine + 1]); + const currentLineString = copy.splice(currentLine + 1, 1); + copy[currentLine] += currentLineString; + } + } else { + copy[currentLine] = copy[currentLine].slice(0, cursorPosition) + copy[currentLine].slice(cursorPosition + 1); + this.offsetX++; + } + this.value = copy.join('\n'); + } + } + } } else if (ch) { if (!/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(ch)) { if (this.offsetX === 0 && this.offsetY === 0){ diff --git a/package.json b/package.json index 31c5c453..423265e5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "semi-blessed", "description": "A fork of BLESSED library with extra features.", "author": "Christopher Jeffrey", - "version": "1.0.2", + "version": "1.0.3", "license": "MIT", "main": "./lib/blessed.js", "bin": "./bin/tput.js", From 07e8f43d464fd0e86afbaca35f90061bb41c9766 Mon Sep 17 00:00:00 2001 From: Pavel Nekrasov Date: Wed, 23 Oct 2024 14:33:31 +0200 Subject: [PATCH 7/8] fix align issue for text elements --- lib/widgets/text.js | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/widgets/text.js b/lib/widgets/text.js index c3b44b22..5ecde3f4 100644 --- a/lib/widgets/text.js +++ b/lib/widgets/text.js @@ -8,8 +8,8 @@ * Modules */ -var Node = require('./node'); -var Element = require('./element'); +var Node = require("./node"); +var Element = require("./element"); /** * Text @@ -20,13 +20,13 @@ function Text(options) { return new Text(options); } options = options || {}; - options.shrink = true; + options.shrink = "shrink" in options ? options.shrink : true; Element.call(this, options); } Text.prototype.__proto__ = Element.prototype; -Text.prototype.type = 'text'; +Text.prototype.type = "text"; /** * Expose diff --git a/package.json b/package.json index 423265e5..f73f57a6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "semi-blessed", "description": "A fork of BLESSED library with extra features.", "author": "Christopher Jeffrey", - "version": "1.0.3", + "version": "1.0.4", "license": "MIT", "main": "./lib/blessed.js", "bin": "./bin/tput.js", From cdf7c817e31b7a56533087d09a5f58fb915fe5ea Mon Sep 17 00:00:00 2001 From: Pavel Nekrasov Date: Wed, 6 Nov 2024 14:43:19 +0100 Subject: [PATCH 8/8] fix wrap text area --- lib/widgets/textarea.js | 195 ++++++++++++++++++++++++++-------------- package.json | 2 +- 2 files changed, 131 insertions(+), 66 deletions(-) diff --git a/lib/widgets/textarea.js b/lib/widgets/textarea.js index b938ba2b..67ac49c0 100644 --- a/lib/widgets/textarea.js +++ b/lib/widgets/textarea.js @@ -76,6 +76,11 @@ Textarea.prototype.getCursor = function(){ return {x: this.offsetX, y: this.offsetY}; } +Textarea.prototype.setCursor = function(x, y){ + this.offsetX = x; + this.offsetY = y; +} + Textarea.prototype.moveCursor = function(x, y){ var prevLine = (this._clines.length - 1) + this.offsetY; let sync = false; @@ -95,7 +100,6 @@ Textarea.prototype.moveCursor = function(x, y){ this.offsetX = x; } this._updateCursor(true); - this.screen.render(); } @@ -246,11 +250,12 @@ Textarea.prototype._listener = function(ch, key) { if (key.name === 'enter') { ch = '\n'; } + const cursor = this.getCursor(); // TODO: Handle directional keys. if (key.name === 'left' || key.name === 'right' - || key.name === 'up' || key.name === 'down') { - var cursor = this.getCursor(); + || key.name === 'up' || key.name === 'down' + || key.name === 'end'|| key.name === 'home') { if (key.name === "left") { cursor.x--; @@ -262,6 +267,14 @@ Textarea.prototype._listener = function(ch, key) { } else if (key.name === "down") { cursor.y++; } + + if (key.name === "end") { + cursor.x = 0; + } else if (key.name === "home") { + const currentLine = (this._clines.length - 1) + this.offsetY + const currentLineLength = this.strWidth(this._clines[currentLine] ?? '') + cursor.x = -currentLineLength; + } this.moveCursor(cursor.x, cursor.y); } @@ -277,93 +290,145 @@ Textarea.prototype._listener = function(ch, key) { } else if (key.name === 'backspace') { if (this.value.length) { if (this.screen.fullUnicode) { - /*if (unicode.isSurrogate(this.value, this.value.length - 2)) { - // || unicode.isCombining(this.value, this.value.length - 1)) { - this.value = this.value.slice(0, -2); - } else { - this.value = this.value.slice(0, -1); - }*/ } else { - if (this.offsetX === 0 && this.offsetY === 0){ + if (cursor.x === 0 && cursor.y === 0){ this.value = this.value.slice(0, -1); - } else { - const currentLine = (this._clines.length - 1) + this.offsetY - const copy = this._clines.slice(); - const cursorPosition = this.strWidth(copy[currentLine]) + this.offsetX; - if (copy[currentLine] === ''){ - copy.splice(currentLine, 1); - } else if (cursorPosition === 0) { + } else { + + const realLines = this._clines.real.slice(); + const fakeLines = this._clines.fake.slice(); + const mapper = this._clines.rtof; + + const currentLine = (realLines.length - 1) + cursor.y; + + const fakeLineIndex = mapper[currentLine]; + + let fakeCursorPosition = 0; + for (let i = 0; i <= currentLine; i++) { + if (mapper[i] === fakeLineIndex) { + fakeCursorPosition += this.strWidth(realLines[i]); + } + } + fakeCursorPosition += cursor.x; + + let realCursorPosition = this.strWidth(realLines[currentLine]) + cursor.x; + + if (fakeLines[fakeLineIndex] === ''){ + fakeLines.splice(fakeLineIndex, 1); + } else if (cursor.x === -this.strWidth(realLines[currentLine])) { if (currentLine > 0){ - const currentLineString = copy.splice(currentLine, 1); - copy[currentLine - 1] += currentLineString; + const lineLengthBefore = this.strWidth(realLines[currentLine - 1] ?? '') + + if (mapper[currentLine] !== mapper[currentLine - 1]){ + const currentLineString = fakeLines.splice(fakeLineIndex, 1); + fakeLines[fakeLineIndex - 1] += currentLineString; + } else { + + } + + const predict = this._wrapContent(fakeLines.join('\n'), this.width - this.iwidth) + + cursor.x = -(this.strWidth(predict[currentLine - 1] ?? '') - lineLengthBefore); + if (predict.real.length === realLines.length){ + cursor.y--; + } } } else { - copy[currentLine] = copy[currentLine].slice(0, cursorPosition - 1) + copy[currentLine].slice(cursorPosition); + fakeLines[fakeLineIndex] = fakeLines[fakeLineIndex].slice(0, fakeCursorPosition - 1) + fakeLines[fakeLineIndex].slice(fakeCursorPosition); + const predict = this._wrapContent(fakeLines.join('\n'), this.width - this.iwidth) + cursor.x = -(this.strWidth(predict.real[currentLine]) - realCursorPosition + 1); + if (predict.real.length !== realLines.length){ + cursor.y++; + } + } - this.value = copy.join('\n'); + this.value = fakeLines.join('\n'); + this.setCursor(cursor.x, cursor.y); } } } } else if (key.name === 'delete') { if (this.value.length) { if (this.screen.fullUnicode) { - /*if (unicode.isSurrogate(this.value, this.value.length - 2)) { - // || unicode.isCombining(this.value, this.value.length - 1)) { - this.value = this.value.slice(0, -2); - } else { - this.value = this.value.slice(0, -1); - }*/ } else { - const currentLine = (this._clines.length - 1) + this.offsetY - if (this.offsetX === 0 && this.offsetY === 0){ - //this.value = this.value.slice(1); + const currentLine = (this._clines.length - 1) + cursor.y + if (cursor.x === 0 && cursor.y === 0){ + } else { - const copy = this._clines.slice(); - const cursorPosition = this.strWidth(copy[currentLine]) + this.offsetX; - if (copy[currentLine] === ''){ - const nextLineLength = this.strWidth(copy[currentLine + 1] ?? '') - copy.splice(currentLine, 1); - this.offsetY++; - this.offsetX = -nextLineLength; - } else if (cursorPosition === this.strWidth(copy[currentLine])) { - if (currentLine < copy.length - 1){ - this.offsetY++; - this.offsetX = -this.strWidth(copy[currentLine + 1]); - const currentLineString = copy.splice(currentLine + 1, 1); - copy[currentLine] += currentLineString; - } + const realLines = this._clines.real.slice(); + const fakeLines = this._clines.fake.slice(); + const mapper = this._clines.rtof; + + const currentLine = (realLines.length - 1) + cursor.y + + const fakeLineIndex = mapper[currentLine]; + + let fakeCursorPosition = 0; + for (let i = 0; i <= currentLine; i++) { + if (mapper[i] === fakeLineIndex) { + fakeCursorPosition += this.strWidth(realLines[i]); + } + } + fakeCursorPosition += cursor.x; + + let realCursorPosition = this.strWidth(realLines[currentLine]) + cursor.x; + + if (fakeLines[fakeLineIndex] === ''){ + const nextLineLength = this.strWidth(fakeLines[fakeLineIndex + 1] ?? '') + fakeLines.splice(fakeLineIndex, 1); + cursor.y++; + cursor.x = -nextLineLength; } else { - copy[currentLine] = copy[currentLine].slice(0, cursorPosition) + copy[currentLine].slice(cursorPosition + 1); - this.offsetX++; + if (fakeLineIndex < fakeLines.length - 1){ + if (cursor.x === -this.strWidth(realLines[currentLine])) { + fakeLines[fakeLineIndex] = fakeLines[fakeLineIndex].substring(1); + } else{ + fakeLines[fakeLineIndex] = fakeLines[fakeLineIndex].slice(0, fakeCursorPosition) + fakeLines[fakeLineIndex].slice(fakeCursorPosition + 1); + } + const predict = this._wrapContent(fakeLines.join('\n'), this.width - this.iwidth) + cursor.x = -(this.strWidth(predict.real[currentLine]) - realCursorPosition); + if (predict.real.length !== realLines.length){ + cursor.y++; + } + } } - this.value = copy.join('\n'); + this.value = fakeLines.join('\n'); + this.setCursor(cursor.x, cursor.y); } } } } else if (ch) { if (!/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(ch)) { - if (this.offsetX === 0 && this.offsetY === 0){ + if (cursor.x === 0 && cursor.y === 0){ this.value += ch; - } else if (this.offsetX >= (this.value.length * -1)) { - const currentLine = (this._clines.length - 1) + this.offsetY - const copy = this._clines.slice(); - const cursorPosition = copy[currentLine].length + this.offsetX; - const maxCharacters = this.width - this.iwidth - 1; - for (let i = currentLine; i < copy.length; i++){ - let value = currentLine == i ? copy[i].slice(0, cursorPosition) + ch + copy[i].slice(cursorPosition) : copy[i]; - if (this.strWidth(value) >= maxCharacters){ - const newPart = value.slice(-1) - copy[i] = value.slice(0, -1) - if (copy[i + 1] === undefined){ - this.offsetY--; - } - copy[i + 1] = newPart + (copy[i + 1] ?? ""); - }else{ - copy[i] = value; + } else if (cursor.x >= (this.value.length * -1)) { + const realLines = this._clines.real.slice(); + const fakeLines = this._clines.fake.slice(); + const mapper = this._clines.rtof; + + const currentLine = (realLines.length - 1) + cursor.y + + const fakeLineIndex = mapper[currentLine]; + let fakeCursorPosition = 0; + for (let i = 0; i <= currentLine; i++) { + if (mapper[i] === fakeLineIndex) { + fakeCursorPosition += this.strWidth(realLines[i]); + } + } + fakeCursorPosition += cursor.x; + + fakeLines[fakeLineIndex] = fakeLines[fakeLineIndex].slice(0, fakeCursorPosition) + ch + fakeLines[fakeLineIndex].slice(fakeCursorPosition); + + const predict = this._wrapContent(fakeLines.join('\n'), this.width - this.iwidth) + if (ch === '\n'){ + if (predict.real.length === realLines.length){ + cursor.y++; } + cursor.x = -this.strWidth(predict[predict.length - 1 + cursor.y]); } - this.value = copy.join('\n'); + this.value = fakeLines.join('\n'); + this.setCursor(cursor.x, cursor.y); } } } diff --git a/package.json b/package.json index f73f57a6..f650dd96 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "semi-blessed", "description": "A fork of BLESSED library with extra features.", "author": "Christopher Jeffrey", - "version": "1.0.4", + "version": "1.0.5", "license": "MIT", "main": "./lib/blessed.js", "bin": "./bin/tput.js",