* Fix line feed losing a character
* Fix wrapping when tabs are involved
This commit is contained in:
parent
8a75dbc91f
commit
2632c150ac
|
@ -187,20 +187,25 @@ function MultiLineEditTextView2(options) {
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getOutputText = function(startIndex, endIndex, includeEol) {
|
this.getTextLines = function(startIndex, endIndex) {
|
||||||
var lines;
|
var lines;
|
||||||
if(startIndex === endIndex) {
|
if(startIndex === endIndex) {
|
||||||
lines = [ self.textLines[startIndex] ];
|
lines = [ self.textLines[startIndex] ];
|
||||||
} else {
|
} else {
|
||||||
lines = self.textLines.slice(startIndex, endIndex + 1); // "slice extracts up to but not including end."
|
lines = self.textLines.slice(startIndex, endIndex + 1); // "slice extracts up to but not including end."
|
||||||
}
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getOutputText = function(startIndex, endIndex, includeEol) {
|
||||||
|
var lines = self.getTextLines(startIndex, endIndex);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Convert lines to contiguous string -- all expanded
|
// Convert lines to contiguous string -- all expanded
|
||||||
// tabs put back to single '\t' characters.
|
// tabs put back to single '\t' characters.
|
||||||
//
|
//
|
||||||
var text = '';
|
var text = '';
|
||||||
var re = new RegExp('\\t{' + (self.tabWidth - 1) + '}', 'g');
|
var re = new RegExp('\\t{1,' + (self.tabWidth) + '}', 'g');
|
||||||
for(var i = 0; i < lines.length; ++i) {
|
for(var i = 0; i < lines.length; ++i) {
|
||||||
text += lines[i].text.replace(re, '\t');
|
text += lines[i].text.replace(re, '\t');
|
||||||
if(includeEol && lines[i].eol) {
|
if(includeEol && lines[i].eol) {
|
||||||
|
@ -210,19 +215,49 @@ function MultiLineEditTextView2(options) {
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getContiguousText = function(startIndex, endIndex, includeEol) {
|
||||||
|
var lines = self.getTextLines(startIndex, endIndex);
|
||||||
|
var text = '';
|
||||||
|
for(var i = 0; i < lines.length; ++i) {
|
||||||
|
text += lines[i].text;
|
||||||
|
if(includeEol && lines[i].eol) {
|
||||||
|
text += '\n'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
|
||||||
this.replaceCharacterInText = function(c, index, col) {
|
this.replaceCharacterInText = function(c, index, col) {
|
||||||
self.textLines[index].text = strUtil.replaceAt(
|
self.textLines[index].text = strUtil.replaceAt(
|
||||||
self.textLines[index].text, col, c);
|
self.textLines[index].text, col, c);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.insertCharacterInText = function(c, index, col) {
|
this.editTextAtPosition = function(editAction, text, index, col) {
|
||||||
|
switch(editAction) {
|
||||||
|
case 'insert' :
|
||||||
|
self.insertCharactersInText(text, index, col);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'deleteForward' :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'deleteBack' :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'replace' :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.insertCharactersInText = function(c, index, col) {
|
||||||
self.textLines[index].text = [
|
self.textLines[index].text = [
|
||||||
self.textLines[index].text.slice(0, col),
|
self.textLines[index].text.slice(0, col),
|
||||||
c,
|
c,
|
||||||
self.textLines[index].text.slice(col)
|
self.textLines[index].text.slice(col)
|
||||||
].join('');
|
].join('');
|
||||||
|
|
||||||
self.cursorPos.col++;
|
//self.cursorPos.col++;
|
||||||
|
self.cursorPos.col += c.length;
|
||||||
|
|
||||||
var cursorOffset;
|
var cursorOffset;
|
||||||
var absPos;
|
var absPos;
|
||||||
|
@ -234,15 +269,24 @@ function MultiLineEditTextView2(options) {
|
||||||
// formatted array.
|
// formatted array.
|
||||||
//
|
//
|
||||||
var nextEolIndex = self.getNextEndOfLineIndex(index);
|
var nextEolIndex = self.getNextEndOfLineIndex(index);
|
||||||
var wrapped = self.wordWrapSingleLine(self.getOutputText(index, nextEolIndex));
|
var wrapped = self.wordWrapSingleLine(self.getContiguousText(index, nextEolIndex), 'tabsIntact')
|
||||||
var newLines = wrapped.wrapped;
|
var newLines = wrapped.wrapped;
|
||||||
|
|
||||||
|
/*
|
||||||
|
console.log(strUtil.debugEscapedString(self.getText(index)) + ' / ' + self.getText(index).length)
|
||||||
|
console.log(strUtil.debugEscapedString(self.getOutputText(index, nextEolIndex)))
|
||||||
|
console.log(newLines)
|
||||||
|
console.log(newLines[0].length)
|
||||||
|
console.log(strUtil.debugEscapedString(self.getContiguousText(index, nextEolIndex)))
|
||||||
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// If our cursor was within the bounds of the last wrapped word
|
// If our cursor was within the bounds of the last wrapped word
|
||||||
// we'll want to adjust the cursor to the same relative position
|
// we'll want to adjust the cursor to the same relative position
|
||||||
// on the next line.
|
// on the next line.
|
||||||
//
|
//
|
||||||
var lastCol = self.cursorPos.col - 1;
|
//var lastCol = self.cursorPos.col - 1;
|
||||||
|
var lastCol = self.cursorPos.col - c.length;
|
||||||
if(lastCol >= wrapped.firstWrapRange.start && lastCol <= wrapped.firstWrapRange.end) {
|
if(lastCol >= wrapped.firstWrapRange.start && lastCol <= wrapped.firstWrapRange.end) {
|
||||||
cursorOffset = self.cursorPos.col - wrapped.firstWrapRange.start;
|
cursorOffset = self.cursorPos.col - wrapped.firstWrapRange.start;
|
||||||
}
|
}
|
||||||
|
@ -260,11 +304,13 @@ function MultiLineEditTextView2(options) {
|
||||||
self.redrawRows(self.cursorPos.row, self.dimens.height);
|
self.redrawRows(self.cursorPos.row, self.dimens.height);
|
||||||
|
|
||||||
if(!_.isUndefined(cursorOffset)) {
|
if(!_.isUndefined(cursorOffset)) {
|
||||||
|
console.log('cursorOffset=' + cursorOffset)
|
||||||
self.cursorBeginOfNextLine();
|
self.cursorBeginOfNextLine();
|
||||||
self.cursorPos.col += cursorOffset;
|
self.cursorPos.col += cursorOffset;
|
||||||
self.client.term.write(ansi.right(cursorOffset));
|
self.client.term.write(ansi.right(cursorOffset));
|
||||||
} else {
|
} else {
|
||||||
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
|
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
|
||||||
|
console.log('absPos=' + JSON.stringify(absPos))
|
||||||
self.client.term.write(ansi.goto(absPos.row, absPos.col));
|
self.client.term.write(ansi.goto(absPos.row, absPos.col));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -275,7 +321,7 @@ function MultiLineEditTextView2(options) {
|
||||||
self.client.term.write(
|
self.client.term.write(
|
||||||
ansi.hideCursor() +
|
ansi.hideCursor() +
|
||||||
self.getSGRFor('text') +
|
self.getSGRFor('text') +
|
||||||
self.getRenderText(index).slice(self.cursorPos.col - 1) +
|
self.getRenderText(index).slice(self.cursorPos.col - c.length) +
|
||||||
ansi.goto(absPos.row, absPos.col) +
|
ansi.goto(absPos.row, absPos.col) +
|
||||||
ansi.showCursor()
|
ansi.showCursor()
|
||||||
);
|
);
|
||||||
|
@ -290,19 +336,12 @@ function MultiLineEditTextView2(options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.calculateTabStops = function() {
|
this.calculateTabStops = function() {
|
||||||
//
|
|
||||||
// :TODO: A system like this may be better for tabs:
|
|
||||||
// 1) Calculate tab stops
|
|
||||||
// 2) On movement/etc.: find next/prev or closest for up/down
|
|
||||||
//
|
|
||||||
// http://stackoverflow.com/questions/8584902/get-closest-number-out-of-array
|
|
||||||
self.tabStops = [ 0 ];
|
self.tabStops = [ 0 ];
|
||||||
var col = 0;
|
var col = 0;
|
||||||
while(col < self.dimens.width) {
|
while(col < self.dimens.width) {
|
||||||
col += self.getRemainingTabWidth(col);
|
col += self.getRemainingTabWidth(col);
|
||||||
self.tabStops.push(col);
|
self.tabStops.push(col);
|
||||||
}
|
}
|
||||||
console.log(self.tabStops)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getNextTabStop = function(col) {
|
this.getNextTabStop = function(col) {
|
||||||
|
@ -322,7 +361,12 @@ function MultiLineEditTextView2(options) {
|
||||||
return new Array(self.getRemainingTabWidth(col)).join(expandChar);
|
return new Array(self.getRemainingTabWidth(col)).join(expandChar);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.wordWrapSingleLine = function(s, width) {
|
this.wordWrapSingleLine = function(s, tabHandling, width) {
|
||||||
|
tabHandling = tabHandling || 'expandTabs';
|
||||||
|
if(!_.isNumber(width)) {
|
||||||
|
width = self.dimens.width;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Notes
|
// Notes
|
||||||
// * Sublime Text 3 for example considers spaces after a word
|
// * Sublime Text 3 for example considers spaces after a word
|
||||||
|
@ -346,8 +390,8 @@ function MultiLineEditTextView2(options) {
|
||||||
var word;
|
var word;
|
||||||
|
|
||||||
function addWord() {
|
function addWord() {
|
||||||
word.match(new RegExp('.{0,' + self.dimens.width + '}', 'g')).forEach(function wrd(w) {
|
word.match(new RegExp('.{0,' + width + '}', 'g')).forEach(function wrd(w) {
|
||||||
if(results.wrapped[i].length + w.length >= self.dimens.width) {
|
if(results.wrapped[i].length + w.length >= width) {
|
||||||
if(0 === i) {
|
if(0 === i) {
|
||||||
results.firstWrapRange = { start : wordStart, end : wordStart + w.length };
|
results.firstWrapRange = { start : wordStart, end : wordStart + w.length };
|
||||||
}
|
}
|
||||||
|
@ -372,7 +416,11 @@ function MultiLineEditTextView2(options) {
|
||||||
//
|
//
|
||||||
// Nice info here: http://c-for-dummies.com/blog/?p=424
|
// Nice info here: http://c-for-dummies.com/blog/?p=424
|
||||||
//
|
//
|
||||||
|
if('expandTabs' === tabHandling) {
|
||||||
word += self.expandTab(results.wrapped[i].length + word.length, '\t') + '\t';
|
word += self.expandTab(results.wrapped[i].length + word.length, '\t') + '\t';
|
||||||
|
} else {
|
||||||
|
word += m[0];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,8 +437,8 @@ function MultiLineEditTextView2(options) {
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
// :TODO: Change this to (text, row, col) & make proper adjustments
|
// :TODO: rename to insertRawText()
|
||||||
this.insertText = function(text, index, col) {
|
this.insertRawText = function(text, index, col) {
|
||||||
//
|
//
|
||||||
// Perform the following on |text|:
|
// Perform the following on |text|:
|
||||||
// * Normalize various line feed formats -> \n
|
// * Normalize various line feed formats -> \n
|
||||||
|
@ -429,7 +477,7 @@ function MultiLineEditTextView2(options) {
|
||||||
var wrapped;
|
var wrapped;
|
||||||
|
|
||||||
for(var i = 0; i < text.length; ++i) {
|
for(var i = 0; i < text.length; ++i) {
|
||||||
wrapped = self.wordWrapSingleLine(text[i], self.dimens.width).wrapped;
|
wrapped = self.wordWrapSingleLine(text[i], 'expandTabs', self.dimens.width).wrapped;
|
||||||
|
|
||||||
for(var j = 0; j < wrapped.length - 1; ++j) {
|
for(var j = 0; j < wrapped.length - 1; ++j) {
|
||||||
self.textLines.splice(index++, 0, { text : wrapped[j] } );
|
self.textLines.splice(index++, 0, { text : wrapped[j] } );
|
||||||
|
@ -469,7 +517,7 @@ function MultiLineEditTextView2(options) {
|
||||||
self.cursorPos.col++;
|
self.cursorPos.col++;
|
||||||
self.client.term.write(c);
|
self.client.term.write(c);
|
||||||
} else {
|
} else {
|
||||||
self.insertCharacterInText(c, index, self.cursorPos.col);
|
self.insertCharactersInText(c, index, self.cursorPos.col);
|
||||||
|
|
||||||
/*if(self.cursorPos.col >= self.dimens.width) {
|
/*if(self.cursorPos.col >= self.dimens.width) {
|
||||||
console.log('next line')
|
console.log('next line')
|
||||||
|
@ -569,10 +617,11 @@ function MultiLineEditTextView2(options) {
|
||||||
// Break up text from cursor position, redraw, and update cursor
|
// Break up text from cursor position, redraw, and update cursor
|
||||||
// position to start of next line
|
// position to start of next line
|
||||||
//
|
//
|
||||||
|
// :TODO: this needs converted to use the getContigousText() and such
|
||||||
var index = self.getTextLinesIndex();
|
var index = self.getTextLinesIndex();
|
||||||
var nextEolIndex = self.getNextEndOfLineIndex(index);
|
var nextEolIndex = self.getNextEndOfLineIndex(index);
|
||||||
var text = self.getOutputText(index, nextEolIndex);
|
var text = self.getOutputText(index, nextEolIndex);
|
||||||
var newLines = self.wordWrapSingleLine(text.slice(self.cursorPos.col + 1)).wrapped;
|
var newLines = self.wordWrapSingleLine(text.slice(self.cursorPos.col)).wrapped;
|
||||||
|
|
||||||
newLines.unshift( { text : text.slice(0, self.cursorPos.col), eol : true } );
|
newLines.unshift( { text : text.slice(0, self.cursorPos.col), eol : true } );
|
||||||
for(var i = 1; i < newLines.length; ++i) {
|
for(var i = 1; i < newLines.length; ++i) {
|
||||||
|
@ -595,8 +644,10 @@ function MultiLineEditTextView2(options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.keyPressTab = function() {
|
this.keyPressTab = function() {
|
||||||
|
// :TODO: Seems tabs are counted as words when wrapping... they should probably break @ nearest
|
||||||
|
// full tab if possible? Look into how Sublime handles this.
|
||||||
var index = self.getTextLinesIndex();
|
var index = self.getTextLinesIndex();
|
||||||
self.insertCharacterInText(self.expandTab(self.cursorPos.col, '\t'), index, self.cursorPos.col);
|
self.insertCharactersInText(self.expandTab(self.cursorPos.col, '\t') + '\t', index, self.cursorPos.col);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.keyPressBackspace = function() {
|
this.keyPressBackspace = function() {
|
||||||
|
@ -647,7 +698,6 @@ function MultiLineEditTextView2(options) {
|
||||||
var newCol = self.tabStops.reduce(function r(prev, curr) {
|
var newCol = self.tabStops.reduce(function r(prev, curr) {
|
||||||
return (Math.abs(curr - self.cursorPos.col) < Math.abs(prev - self.cursorPos.col) ? curr : prev);
|
return (Math.abs(curr - self.cursorPos.col) < Math.abs(prev - self.cursorPos.col) ? curr : prev);
|
||||||
});
|
});
|
||||||
console.log('newCol=' + newCol)
|
|
||||||
|
|
||||||
if(newCol > self.cursorPos.col) {
|
if(newCol > self.cursorPos.col) {
|
||||||
move = newCol - self.cursorPos.col;
|
move = newCol - self.cursorPos.col;
|
||||||
|
@ -757,6 +807,12 @@ function MultiLineEditTextView2(options) {
|
||||||
|
|
||||||
require('util').inherits(MultiLineEditTextView2, View);
|
require('util').inherits(MultiLineEditTextView2, View);
|
||||||
|
|
||||||
|
MultiLineEditTextView2.prototype.setWidth = function(width) {
|
||||||
|
MultiLineEditTextView2.super_.prototype.setWidth.call(this, width);
|
||||||
|
|
||||||
|
this.calculateTabStops();
|
||||||
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.redraw = function() {
|
MultiLineEditTextView2.prototype.redraw = function() {
|
||||||
MultiLineEditTextView2.super_.prototype.redraw.call(this);
|
MultiLineEditTextView2.super_.prototype.redraw.call(this);
|
||||||
|
|
||||||
|
@ -774,10 +830,11 @@ MultiLineEditTextView2.prototype.setText = function(text) {
|
||||||
//text = "Tab:\r\n\tA\tB\tC\tD\tE\tF\tG\r\n reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long word!!!";
|
//text = "Tab:\r\n\tA\tB\tC\tD\tE\tF\tG\r\n reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long word!!!";
|
||||||
text = require('fs').readFileSync('/home/nuskooler/Downloads/test_text.txt', { encoding : 'utf-8'});
|
text = require('fs').readFileSync('/home/nuskooler/Downloads/test_text.txt', { encoding : 'utf-8'});
|
||||||
|
|
||||||
this.insertText(text);//, 0, 0);
|
this.insertRawText(text);//, 0, 0);
|
||||||
this.cursorEndOfDocument();
|
this.cursorEndOfDocument();
|
||||||
console.log(this.textLines)
|
console.log(this.textLines)
|
||||||
console.log(this.calculateTabStops())
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var HANDLED_SPECIAL_KEYS = [
|
var HANDLED_SPECIAL_KEYS = [
|
||||||
|
|
|
@ -8,6 +8,7 @@ exports.stylizeString = stylizeString;
|
||||||
exports.pad = pad;
|
exports.pad = pad;
|
||||||
exports.replaceAt = replaceAt;
|
exports.replaceAt = replaceAt;
|
||||||
exports.isPrintable = isPrintable;
|
exports.isPrintable = isPrintable;
|
||||||
|
exports.debugEscapedString = debugEscapedString;
|
||||||
|
|
||||||
// :TODO: create Unicode verison of this
|
// :TODO: create Unicode verison of this
|
||||||
var VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
var VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
||||||
|
@ -169,3 +170,7 @@ function stringLength(s) {
|
||||||
// :TODO: See https://mathiasbynens.be/notes/javascript-unicode
|
// :TODO: See https://mathiasbynens.be/notes/javascript-unicode
|
||||||
return s.length;
|
return s.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function debugEscapedString(s) {
|
||||||
|
return JSON.stringify(s).slice(1, -1);
|
||||||
|
}
|
Loading…
Reference in New Issue