* Movement working pretty well with tabs, etc.

* Handling of linefeed (enter key)
* Start work on tab key press
This commit is contained in:
Bryan Ashby 2015-06-13 21:49:12 -06:00
parent dc883ac6e6
commit 8a75dbc91f
1 changed files with 160 additions and 123 deletions

View File

@ -52,7 +52,7 @@ var SPECIAL_KEY_MAP_DEFAULT = {
exit : [ 'esc' ],
backspace : [ 'backspace' ],
del : [ 'del' ],
tabs : [ 'tab' ],
tab : [ 'tab' ],
up : [ 'up arrow' ],
down : [ 'down arrow' ],
end : [ 'end' ],
@ -221,6 +221,65 @@ function MultiLineEditTextView2(options) {
c,
self.textLines[index].text.slice(col)
].join('');
self.cursorPos.col++;
var cursorOffset;
var absPos;
if(self.getText(index).length >= self.dimens.width) {
//
// Past available space -- word wrap from current point
// to the next EOL. Update textLines with the newly
// formatted array.
//
var nextEolIndex = self.getNextEndOfLineIndex(index);
var wrapped = self.wordWrapSingleLine(self.getOutputText(index, nextEolIndex));
var newLines = wrapped.wrapped;
//
// If our cursor was within the bounds of the last wrapped word
// we'll want to adjust the cursor to the same relative position
// on the next line.
//
var lastCol = self.cursorPos.col - 1;
if(lastCol >= wrapped.firstWrapRange.start && lastCol <= wrapped.firstWrapRange.end) {
cursorOffset = self.cursorPos.col - wrapped.firstWrapRange.start;
}
for(var i = 0; i < newLines.length; ++i) {
newLines[i] = { text : newLines[i] };
}
newLines[newLines.length - 1].eol = true;
Array.prototype.splice.apply(
self.textLines,
[ index, (nextEolIndex - index) + 1 ].concat(newLines));
// redraw from current row to end of visible area
self.redrawRows(self.cursorPos.row, self.dimens.height);
if(!_.isUndefined(cursorOffset)) {
self.cursorBeginOfNextLine();
self.cursorPos.col += cursorOffset;
self.client.term.write(ansi.right(cursorOffset));
} else {
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
self.client.term.write(ansi.goto(absPos.row, absPos.col));
}
} else {
//
// We must only redraw from col -> end of current visible line
//
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
self.client.term.write(
ansi.hideCursor() +
self.getSGRFor('text') +
self.getRenderText(index).slice(self.cursorPos.col - 1) +
ansi.goto(absPos.row, absPos.col) +
ansi.showCursor()
);
}
};
this.getRemainingTabWidth = function(col) {
@ -237,7 +296,7 @@ function MultiLineEditTextView2(options) {
// 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 = [];
self.tabStops = [ 0 ];
var col = 0;
while(col < self.dimens.width) {
col += self.getRemainingTabWidth(col);
@ -246,6 +305,18 @@ function MultiLineEditTextView2(options) {
console.log(self.tabStops)
};
this.getNextTabStop = function(col) {
var i = self.tabStops.length;
while(self.tabStops[--i] > col);
return self.tabStops[++i];
};
this.getPrevTabStop = function(col) {
var i = self.tabStops.length;
while(self.tabStops[--i] >= col);
return self.tabStops[i];
};
this.expandTab = function(col, expandChar) {
expandChar = expandChar || ' ';
return new Array(self.getRemainingTabWidth(col)).join(expandChar);
@ -379,6 +450,7 @@ function MultiLineEditTextView2(options) {
self.client.term.write(ansi.goto(absPos.row, absPos.col));
};
this.keyPressCharacter = function(c) {
var index = self.getTextLinesIndex();
@ -398,71 +470,6 @@ function MultiLineEditTextView2(options) {
self.client.term.write(c);
} else {
self.insertCharacterInText(c, index, self.cursorPos.col);
self.cursorPos.col++;
var cursorOffset;
var absPos;
if(self.getText(index).length >= self.dimens.width) {
//
// Past available space -- word wrap from current point
// to the next EOL. Update textLines with the newly
// formatted array.
//
var nextEolIndex = self.getNextEndOfLineIndex(index);
var wrapped = self.wordWrapSingleLine(self.getOutputText(index, nextEolIndex));
var newLines = wrapped.wrapped;
/*console.log('--------------Newlines')
console.log(newLines)
console.log('--------------getText')
console.log( [ self.getText(index) ] )*/
//
// If our cursor was within the bounds of the last wrapped word
// we'll want to adjust the cursor to the same relative position
// on the next line.
//
var lastCol = self.cursorPos.col - 1;
if(lastCol >= wrapped.firstWrapRange.start && lastCol <= wrapped.firstWrapRange.end) {
cursorOffset = self.cursorPos.col - wrapped.firstWrapRange.start;
}
for(var i = 0; i < newLines.length; ++i) {
newLines[i] = { text : newLines[i] };
}
newLines[newLines.length - 1].eol = true;
Array.prototype.splice.apply(
self.textLines,
[ index, (nextEolIndex - index) + 1 ].concat(newLines));
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
// redraw from current row to end of visible area
self.redrawRows(self.cursorPos.row, self.dimens.height);
if(!_.isUndefined(cursorOffset)) {
self.cursorBeginOfNextLine();
self.cursorPos.col += cursorOffset;
self.client.term.write(ansi.right(cursorOffset));
} else {
self.client.term.write(ansi.goto(absPos.row, absPos.col));
}
} else {
//
// We must only redraw from col -> end of current visible line
//
absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
self.client.term.write(
ansi.hideCursor() +
self.getSGRFor('text') +
self.getRenderText(index).slice(self.cursorPos.col - 1) +
ansi.goto(absPos.row, absPos.col) +
ansi.showCursor()
);
}
/*if(self.cursorPos.col >= self.dimens.width) {
console.log('next line')
@ -478,8 +485,9 @@ function MultiLineEditTextView2(options) {
self.cursorPos.row--;
self.client.term.write(ansi.up());
// :TODO: self.makeTabAdjustment('up')
self.adjustCursorIfPastEndOfLine(false);
if(!self.adjustCursorToNextTab('up')) {
self.adjustCursorIfPastEndOfLine(false);
}
} else {
self.scrollDocumentDown();
self.adjustCursorIfPastEndOfLine(true);
@ -492,9 +500,9 @@ function MultiLineEditTextView2(options) {
self.cursorPos.row++;
self.client.term.write(ansi.down());
// :TODO: make tab adjustment if needed
self.adjustCursorIfPastEndOfLine(false);
if(!self.adjustCursorToNextTab('down')) {
self.adjustCursorIfPastEndOfLine(false);
}
} else {
self.scrollDocumentUp();
self.adjustCursorIfPastEndOfLine(true);
@ -557,7 +565,28 @@ function MultiLineEditTextView2(options) {
};
this.keyPressLineFeed = function() {
//
// Break up text from cursor position, redraw, and update cursor
// position to start of next line
//
var index = self.getTextLinesIndex();
var nextEolIndex = self.getNextEndOfLineIndex(index);
var text = self.getOutputText(index, nextEolIndex);
var newLines = self.wordWrapSingleLine(text.slice(self.cursorPos.col + 1)).wrapped;
newLines.unshift( { text : text.slice(0, self.cursorPos.col), eol : true } );
for(var i = 1; i < newLines.length; ++i) {
newLines[i] = { text : newLines[i] };
}
newLines[newLines.length - 1].eol = true;
Array.prototype.splice.apply(
self.textLines,
[ index, (nextEolIndex - index) + 1 ].concat(newLines));
// redraw from current row to end of visible area
self.redrawRows(self.cursorPos.row, self.dimens.height);
self.cursorBeginOfNextLine();
};
this.keyPressInsert = function() {
@ -565,6 +594,19 @@ function MultiLineEditTextView2(options) {
self.overtypeMode = !self.overtypeMode;
};
this.keyPressTab = function() {
var index = self.getTextLinesIndex();
self.insertCharacterInText(self.expandTab(self.cursorPos.col, '\t'), index, self.cursorPos.col);
};
this.keyPressBackspace = function() {
};
this.keyPressDel = function() {
};
this.adjustCursorIfPastEndOfLine = function(forceUpdate) {
var eolColumn = self.getTextEndOfLineColumn();
if(self.cursorPos.col > eolColumn) {
@ -577,16 +619,8 @@ function MultiLineEditTextView2(options) {
}
};
this.adjustCursorToNearestTab = function() {
//
// When pressing up or down and landing on a tab, jump
// to the nearest tabstop -- right or left.
//
};
this.adjustCursorToNextTab = function(direction) {
if('\t' === self.getCharacter()) { // :TODO: should probably just be an assert
if('\t' === self.getCharacter()) {
//
// When pressing right or left, jump to the next
// tabstop in that direction.
@ -594,57 +628,42 @@ function MultiLineEditTextView2(options) {
var move;
switch(direction) {
case 'right' :
/*
var i;
for(i = 0; i < self.tabStops.length; ++i) {
if(self.tabStops[i] >= self.cursorPos.col) {
break;
}
}
i = Math.min(self.tabStops.length, i + 1);
move = self.tabStops[i] - self.cursorPos.col;
*/
move = self.getRemainingTabWidth();
move = self.getNextTabStop(self.cursorPos.col) - self.cursorPos.col;
self.cursorPos.col += move;
self.client.term.write(ansi.right(move));
break;
case 'left' :
//
// We'll move up to tabWidth spaces left
//
// return self.tabWidth - (col % self.tabWidth);
//var move = self.tabWidth - 1;
var test = self.tabWidth - self.getRemainingTabWidth();
var text = self.getText();
var col = self.cursorPos.col;
move = 0;
while(move < self.tabWidth - 2) {
if('\t' !== text.charAt(col--)) {
break;
}
move++;
}
/*
var move = self.tabWidth - 1;
for(; col > 0 && move > 0; --col, --move) {
if('\t' !== text.charAt(col)) {
break;
}
}
console.log('curCol=' + self.cursorPos.col + ' / col=' + col)
move = (self.cursorPos.col - col) - 1;
*/
console.log('test=' + test + ' / move=' + move)
move = self.cursorPos.col - self.getPrevTabStop(self.cursorPos.col);
self.cursorPos.col -= move;
self.client.term.write(ansi.left(move));
break;
case 'up' :
case 'down' :
//
// To nearest tabstop
//
var newCol = self.tabStops.reduce(function r(prev, curr) {
return (Math.abs(curr - self.cursorPos.col) < Math.abs(prev - self.cursorPos.col) ? curr : prev);
});
console.log('newCol=' + newCol)
if(newCol > self.cursorPos.col) {
move = newCol - self.cursorPos.col;
self.cursorPos.col += move;
self.client.term.write(ansi.right(move));
} else if(newCol < self.cursorPos.col) {
move = self.cursorPos.col - newCol;
self.cursorPos.col -= move;
self.client.term.write(ansi.left(move));
}
break;
}
return true;
}
return false; // did not fall on a tab
};
this.cursorStartOfDocument = function() {
@ -695,6 +714,22 @@ function MultiLineEditTextView2(options) {
}
};
/*
this.cusorEndOfNextLine = function() {
var linesBelow = self.getRemainingLinesBelowRow();
if(linesBelow > 0) {
var lastVisibleRow = Math.min(self.dimens.height, self.textLines.length) - 1;
if(self.cursorPos.row < lastVisibleRow) {
self.cursorPos.row++;
} else {
self.scrollDocumentUp();
}
self.keyPressEnd(); // same as pressing 'end'
}
};
*/
this.scrollDocumentUp = function() {
//
// Note: We scroll *up* when the cursor goes *down* beyond
@ -737,7 +772,7 @@ MultiLineEditTextView2.prototype.setFocus = function(focused) {
MultiLineEditTextView2.prototype.setText = function(text) {
this.textLines = [ ];
//text = "Tab:\r\n\tA\tB\tC\tD\tE\tF\tG\r\n reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long word!!!";
text = require('fs').readFileSync('/home/bashby/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.cursorEndOfDocument();
@ -751,6 +786,8 @@ var HANDLED_SPECIAL_KEYS = [
'pageUp', 'pageDown',
'lineFeed',
'insert',
'tab',
'backspace', 'del',
];
MultiLineEditTextView2.prototype.onKeyPress = function(ch, key) {