* Code cleanup
* MultiLineEditTextView2 -> MultiLineEditTextView
This commit is contained in:
parent
c1469a1f9c
commit
bb7504a35a
|
@ -11,7 +11,7 @@ var ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView;
|
||||||
var MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView;
|
var MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView;
|
||||||
|
|
||||||
//var MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView;
|
//var MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView;
|
||||||
var MultiLineEditTextView = require('./multi_line_edit_text_view2.js').MultiLineEditTextView2;
|
var MultiLineEditTextView = require('./multi_line_edit_text_view2.js').MultiLineEditTextView;
|
||||||
|
|
||||||
var Config = require('./config.js').config;
|
var Config = require('./config.js').config;
|
||||||
var ansi = require('./ansi_term.js');
|
var ansi = require('./ansi_term.js');
|
||||||
|
|
|
@ -1,518 +0,0 @@
|
||||||
/* jslint node: true */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var View = require('./view.js').View;
|
|
||||||
var miscUtil = require('./misc_util.js');
|
|
||||||
var strUtil = require('./string_util.js');
|
|
||||||
var ansi = require('./ansi_term.js');
|
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
var _ = require('lodash');
|
|
||||||
var GapBuffer = require('gapbuffer').GapBuffer;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Notes
|
|
||||||
// * options.tabSize can be used to resolve \t
|
|
||||||
// * See https://github.com/dominictarr/hipster/issues/15 about insert/delete lines
|
|
||||||
//
|
|
||||||
// Blessed
|
|
||||||
// insertLine: CSR(top, bottom) + CUP(y, 0) + IL(1) + CSR(0, height)
|
|
||||||
// deleteLine: CSR(top, bottom) + CUP(y, 0) + DL(1) + CSR(0, height)
|
|
||||||
// Quick Ansi -- update only what was changed:
|
|
||||||
// https://github.com/dominictarr/quickansi
|
|
||||||
//
|
|
||||||
// This thread is awesome:
|
|
||||||
// https://github.com/dominictarr/hipster/issues/15
|
|
||||||
//
|
|
||||||
// See Atom's implementations
|
|
||||||
// Newer TextDocument
|
|
||||||
// https://github.com/atom/text-document
|
|
||||||
//
|
|
||||||
// Older TextBuffer
|
|
||||||
// http://www.oscon.com/oscon2014/public/schedule/detail/37593
|
|
||||||
//
|
|
||||||
// Span Skip List could be used for mappings of rows/cols (display) to
|
|
||||||
// character offsets in a buffer
|
|
||||||
// https://github.com/atom/span-skip-list
|
|
||||||
|
|
||||||
//
|
|
||||||
// Buffer: Actual text buffer
|
|
||||||
// Transform: Display of soft wrap & tab expansion (e.g. tab -> ' ' * tabWidth)
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// General Design
|
|
||||||
//
|
|
||||||
// * Take any existing input & word wrap into lines[] preserving
|
|
||||||
// formatting characters.
|
|
||||||
// * When drawing, formatting characters are processed but not shown
|
|
||||||
// or processed directly in many cases. E.g., \n is processed but simply
|
|
||||||
// causes us to go to our "next line" visibly.
|
|
||||||
// * Empty/blank lines = \n
|
|
||||||
//
|
|
||||||
exports.MultiLineEditTextView = MultiLineEditTextView;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Some resources & comparisons
|
|
||||||
//
|
|
||||||
// Enthral @ https://github.com/M-griffin/Enthral/blob/master/src/msg_fse.cpp
|
|
||||||
// * Tabs are ignored
|
|
||||||
// * Preview/reading mode processes colors, otherwise just text (e.g. editor)
|
|
||||||
//
|
|
||||||
// x84 @ https://github.com/jquast/x84/blob/master/x84/bbs/editor.py
|
|
||||||
//
|
|
||||||
// Syncronet
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Projects of use/interest:
|
|
||||||
//
|
|
||||||
// https://github.com/atom/text-buffer
|
|
||||||
// http://danieltao.com/lazy.js/
|
|
||||||
// http://www.jbox.dk/downloads/edit.c
|
|
||||||
// https://github.com/slap-editor/slap
|
|
||||||
// https://github.com/chjj/blessed
|
|
||||||
//
|
|
||||||
|
|
||||||
// need self.skipTabs(dir): if pos='\t', skip ahead (in dir) until reg char. This can be used @ up, left, right, down
|
|
||||||
|
|
||||||
function MultiLineEditTextView(options) {
|
|
||||||
|
|
||||||
if(!_.isBoolean(options.acceptsFocus)) {
|
|
||||||
options.acceptsFocus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!_.isBoolean(this.acceptsInput)) {
|
|
||||||
options.acceptsInput = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
View.call(this, options);
|
|
||||||
|
|
||||||
//
|
|
||||||
// defualt tabWidth is 8
|
|
||||||
// See the following:
|
|
||||||
// * http://www.ansi-bbs.org/ansi-bbs2/control_chars/
|
|
||||||
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
|
|
||||||
//
|
|
||||||
this.tabWidth = _.isNumber(options.tabWidth) ? options.tabWidth : 8;
|
|
||||||
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.renderBuffer = [];
|
|
||||||
this.textBuffer = new GapBuffer(1024);
|
|
||||||
|
|
||||||
this.lines = []; // a given line is text...until EOL
|
|
||||||
this.topLineIndex = 0;
|
|
||||||
this.cursorPos = { row : 0, col : 0 }; // relative to view window
|
|
||||||
this.renderStartIndex = 0;
|
|
||||||
|
|
||||||
this.getTabString = function() {
|
|
||||||
return new Array(self.tabWidth).join(' ');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getRenderLine = function(line) {
|
|
||||||
// :TODO: fix tabbing here
|
|
||||||
line = line.replace(self.getReplaceTabsRegExp(), self.getTabString()).replace(/\n/g, '');
|
|
||||||
var remain = self.dimens.width - line.length;
|
|
||||||
if(remain > 0) {
|
|
||||||
line += new Array(remain).join(' ');
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.redrawViewableText = function() {
|
|
||||||
var row = self.position.row;
|
|
||||||
var bottom = row + self.dimens.height;
|
|
||||||
var i = self.topLineIndex;
|
|
||||||
|
|
||||||
self.client.term.write(self.getSGR());
|
|
||||||
|
|
||||||
while(i < self.renderBuffer.length && row < bottom) {
|
|
||||||
self.client.term.write(ansi.goto(row, this.position.col));
|
|
||||||
self.client.term.write(self.getRenderLine(self.renderBuffer[i]));
|
|
||||||
++row;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.wordWrap = function(line) {
|
|
||||||
//
|
|
||||||
// Other implementations:
|
|
||||||
// * http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
|
|
||||||
// * http://james.padolsey.com/snippets/wordwrap-for-javascript/
|
|
||||||
// * http://phpjs.org/functions/wordwrap/
|
|
||||||
// * https://github.com/jonschlinkert/word-wrap
|
|
||||||
//
|
|
||||||
var re = new RegExp(
|
|
||||||
'.{1,' + self.dimens.width + '}(\\s+|$)|\\S+?(\\s+|$)', 'g');
|
|
||||||
return line.match(re) || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.wordWrap3 = function(line, width) {
|
|
||||||
var re = new RegExp('.{1,' + width + '}(\\s+|$)|\\S+?(\\s+|$)', 'g');
|
|
||||||
return line.replace(/\t/g, new Array(self.tabWidth).join('\t')).match(re) || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.updateRenderBuffer = function() {
|
|
||||||
//
|
|
||||||
// We can estimate what is visible:
|
|
||||||
// * Starting point = start of buffer or previous LF from where we were previously
|
|
||||||
// * Ending point = start + width * height (max chars possible)
|
|
||||||
// If this system is kept, this can be optimized as per above
|
|
||||||
//
|
|
||||||
|
|
||||||
self.renderBuffer = [];
|
|
||||||
// :TODO: optimize this with asArray() taking the slice information
|
|
||||||
var lines = self.textBuffer.asArray()//.slice(self.renderStartIndex, self.renderStartIndex + self.dimens.width * self.dimens.height)
|
|
||||||
.join('')
|
|
||||||
.split(/\r\n|\n|\r/g);
|
|
||||||
|
|
||||||
var maxLines = self.dimens.height - self.position.row;
|
|
||||||
|
|
||||||
for(var i = 0; i < lines.length && self.renderBuffer.length < maxLines; ++i) {
|
|
||||||
if(0 === lines[i].length) {
|
|
||||||
self.renderBuffer.push('');
|
|
||||||
} else {
|
|
||||||
Array.prototype.push.apply(self.renderBuffer, self.wordWrap3(lines[i] + '\n', self.dimens.width));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getReplaceTabsRegExp = function() {
|
|
||||||
return new RegExp('\\t{' + (self.tabWidth - 1) + '}', 'g');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getTextBufferPosition = function(row, col) {
|
|
||||||
var replaceTabsRe = self.getReplaceTabsRegExp();
|
|
||||||
var pos = 0;
|
|
||||||
for(var r = 0; r < row; ++r) {
|
|
||||||
if(self.renderBuffer[r].length > 0) {
|
|
||||||
pos += self.renderBuffer[r].replace(replaceTabsRe, '\t').length;
|
|
||||||
} else {
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += self.renderBuffer[row]
|
|
||||||
.slice(0, Math.min(col, self.dimens.width))
|
|
||||||
.replace(replaceTabsRe, '\t')
|
|
||||||
.length;
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getLineTextLength = function(row) {
|
|
||||||
return self.renderBuffer[row].replace(self.getReplaceTabsRegExp(), '\t').replace(/\n/g, '').length;
|
|
||||||
//return self.renderBuffer[row].replace(/\n/g, '').length;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getRenderTextLength = function(row) {
|
|
||||||
return self.renderBuffer[row].replace(/\n/g, '').length;
|
|
||||||
};
|
|
||||||
|
|
||||||
// :TODO: this name makes no sense...
|
|
||||||
this.getLineTextLengthToColumn = function(row, col) {
|
|
||||||
return self.renderBuffer[row].replace(self.getReplaceTabsRegExp(), '\t').replace(/\n/g, '').slice(0, col).length;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getEndOfLineColumn = function(row) {
|
|
||||||
if(!_.isNumber(row)) {
|
|
||||||
row = self.cursorPos.row;
|
|
||||||
}
|
|
||||||
return self.getLineTextLength(row);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getAbsolutePosition = function(row, col) {
|
|
||||||
if(!_.isNumber(row)) {
|
|
||||||
row = self.cursorPos.row;
|
|
||||||
}
|
|
||||||
if(!_.isNumber(col)) {
|
|
||||||
col = self.cursorPos.col;
|
|
||||||
}
|
|
||||||
return { row : self.position.row + row, col : self.position.col + col };
|
|
||||||
};
|
|
||||||
|
|
||||||
// :TODO: rename this to show it is the *buffer*
|
|
||||||
this.getCharAtCursorPosition = function() {
|
|
||||||
var pos = self.getTextBufferPosition(self.cursorPos.row, self.cursorPos.col);
|
|
||||||
return self.textBuffer.get(pos);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getRenderCharAtRowAndColumn = function(row, col) {
|
|
||||||
return self.renderBuffer[row][col];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getRenderCharAtCursorPosition = function() {
|
|
||||||
return self.getRenderCharAtRowAndColumn(self.cursorPos.row, self.cursorPos.col);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getRemainingRowsFromCurrent = function() {
|
|
||||||
return Math.min(self.dimens.height, self.renderBuffer.length) - (self.cursorPos.row + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.moveCursorTo = function(row, col) {
|
|
||||||
var absPos = self.getAbsolutePosition(row, col);
|
|
||||||
self.client.term.write(ansi.goto(absPos.row, absPos.col));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.scrollUp = function(count) {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
this.scrollDown = function(count) {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.cursorMoveJumpTab = function(cursorDir) {
|
|
||||||
if('\t' !== self.getRenderCharAtCursorPosition()) {
|
|
||||||
return; // nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// A few scenarios:
|
|
||||||
// * Cursor just moved up or down and we got dumped in the middle of a tab sequence.
|
|
||||||
// :TODO: document: Jump to nearest tab right/left. This needs some more research
|
|
||||||
// * Cursor moved left or right: We should be on the first \t in either direction & need to jump
|
|
||||||
// * Tabs may expand to start/end of line -- in this case we should move to the next line
|
|
||||||
//
|
|
||||||
// Example tab sequence when up/down (tabSize=8)
|
|
||||||
// Actual: Hello\tWorld!
|
|
||||||
// Render: Hello\t\t\t\t\t\t\t\tWorld!
|
|
||||||
// ^-- cursor up from here
|
|
||||||
//
|
|
||||||
switch(cursorDir) {
|
|
||||||
case 'left' :
|
|
||||||
self.cursorPos.col -= (self.tabWidth - 1);
|
|
||||||
if(self.cursorPos.col <= 0) {
|
|
||||||
self.cursorToEndOfPreviousLine();
|
|
||||||
} else {
|
|
||||||
self.client.term.write(ansi.left(self.tabWidth - 1));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'right' :
|
|
||||||
self.cursorPos.col += (self.tabWidth - 1);
|
|
||||||
if(self.cursorPos.col >= self.dimens.width) {
|
|
||||||
self.cursorToStartOfNextLine();
|
|
||||||
} else {
|
|
||||||
self.client.term.write(ansi.right(self.tabWidth - 1));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'up' :
|
|
||||||
case 'down' :
|
|
||||||
//
|
|
||||||
// We're going to move right, but we need to know where we're at in
|
|
||||||
// in the render buffer expanded tabs
|
|
||||||
//
|
|
||||||
// :TODO: This is not right -- we need to move to *nearest*. Research how
|
|
||||||
// sublime/etc. treat this
|
|
||||||
var col = self.cursorPos.col;
|
|
||||||
var prevTabs = 0;
|
|
||||||
while('\t' === self.getRenderCharAtRowAndColumn(self.cursorPos.row, col--)) {
|
|
||||||
prevTabs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log('prevTabs: ' + prevTabs)
|
|
||||||
var adjust = self.tabWidth - prevTabs;
|
|
||||||
self.cursorPos.col += adjust;
|
|
||||||
self.client.term.write(ansi.right(adjust));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.adjustColumnToEndOfLine = function() {
|
|
||||||
var eolColumn = self.getEndOfLineColumn();
|
|
||||||
if(self.cursorPos.col > eolColumn) {
|
|
||||||
self.cursorPos.col = eolColumn;
|
|
||||||
var absPos = self.getAbsolutePosition(self.cursorPos.row, eolColumn);
|
|
||||||
self.client.term.write(ansi.goto(absPos.row, absPos.col));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.cursorUp = function() {
|
|
||||||
if(self.cursorPos.row > 0) {
|
|
||||||
self.cursorPos.row--;
|
|
||||||
self.client.term.write(ansi.up());
|
|
||||||
|
|
||||||
self.cursorMoveJumpTab('up');
|
|
||||||
} else if(self.topLineIndex > 0) {
|
|
||||||
// :TODO: scroll up if possible to do so
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust to EOL position if needed
|
|
||||||
self.adjustColumnToEndOfLine();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cursorDown = function() {
|
|
||||||
if(self.getRemainingRowsFromCurrent() > 0) {
|
|
||||||
self.cursorPos.row++;
|
|
||||||
self.client.term.write(ansi.down());
|
|
||||||
|
|
||||||
self.cursorMoveJumpTab('down');
|
|
||||||
} else {
|
|
||||||
// :TODO: scroll if possible
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust to EOL position if needed
|
|
||||||
self.adjustColumnToEndOfLine();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cursorLeft = function() {
|
|
||||||
if(self.cursorPos.col > 0) {
|
|
||||||
self.cursorPos.col--;
|
|
||||||
self.client.term.write(ansi.left());
|
|
||||||
|
|
||||||
self.cursorMoveJumpTab('left');
|
|
||||||
} else {
|
|
||||||
self.cursorToEndOfPreviousLine();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cursorRight = function() {
|
|
||||||
var rowVisibleLen = self.renderBuffer[self.cursorPos.row].replace(/\n/g, '').length;
|
|
||||||
var max = Math.min(self.dimens.width, rowVisibleLen - 1);//selfself.getLineTextLength(self.cursorPos.row) - 1);
|
|
||||||
console.log('self.dimens.width: ' + self.dimens.width + ' / lineLength: ' + (self.getLineTextLength(self.cursorPos.row) - 1))
|
|
||||||
if(self.cursorPos.col < max) {
|
|
||||||
self.cursorPos.col++;
|
|
||||||
self.client.term.write(ansi.right());
|
|
||||||
|
|
||||||
// make tab adjustment if necessary
|
|
||||||
self.cursorMoveJumpTab('right');
|
|
||||||
} else {
|
|
||||||
self.cursorToStartOfNextLine();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cursorToEndOfPreviousLine = function() {
|
|
||||||
if(self.cursorPos.row > 0) {
|
|
||||||
self.cursorPos.row--;
|
|
||||||
self.cursorPos.col = self.getRenderTextLength(self.cursorPos.row) - 1;
|
|
||||||
self.moveCursorTo(self.cursorPos.row, self.cursorPos.col);
|
|
||||||
} else {
|
|
||||||
// can we scroll??!!!
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cursorToStartOfNextLine = function() {
|
|
||||||
if(self.getRemainingRowsFromCurrent() > 0) {
|
|
||||||
self.cursorPos.row++;
|
|
||||||
self.cursorPos.col = 0;
|
|
||||||
self.moveCursorTo(self.cursorPos.row, self.cursorPos.col);
|
|
||||||
} else {
|
|
||||||
// :TODO: can we scroll??
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.getLineIndex = function() {
|
|
||||||
return self.topLineIndex + self.cursorPos.row;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.insertCharacterAtCurrentPosition = function(c) {
|
|
||||||
var pos = self.getTextBufferPosition(self.cursorPos.row, self.cursorPos.col);
|
|
||||||
self.cursorPos.col++;
|
|
||||||
if(self.cursorPos.col >= self.dimens.width) {
|
|
||||||
self.cursorToStartOfNextLine();
|
|
||||||
|
|
||||||
}
|
|
||||||
self.client.term.write(c);
|
|
||||||
self.textBuffer.insert(pos, c);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
require('util').inherits(MultiLineEditTextView, View);
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.setPosition = function(pos) {
|
|
||||||
MultiLineEditTextView.super_.prototype.setPosition.call(this, pos);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.redraw = function() {
|
|
||||||
MultiLineEditTextView.super_.prototype.redraw.call(this);
|
|
||||||
|
|
||||||
this.redrawViewableText();
|
|
||||||
//this.client.term.write(this.text);
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.setFocus = function(focused) {
|
|
||||||
|
|
||||||
MultiLineEditTextView.super_.prototype.setFocus.call(this, focused);
|
|
||||||
|
|
||||||
this.moveCursorTo(this.cursorPos.row, this.cursorPos.col);
|
|
||||||
this.client.term.write(this.getSGR());
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.setText = function(text) {
|
|
||||||
//this.cursorPos.row = this.position.row + this.dimens.height;
|
|
||||||
//this.lines = this.wordWrap(text);
|
|
||||||
|
|
||||||
if(this.textBuffer.length > 0) { // :TODO: work around GapBuffer bug: if it's already empty this will cause gapEnd to be undefined
|
|
||||||
this.textBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//this.textBuffer.insertAll(0, text);
|
|
||||||
text = text.replace(/\b/g, '');
|
|
||||||
|
|
||||||
this.textBuffer.insertAll(0, text);
|
|
||||||
|
|
||||||
this.updateRenderBuffer();
|
|
||||||
|
|
||||||
console.log(this.renderBuffer)
|
|
||||||
/*
|
|
||||||
var idx = this.getTextBufferPosition(4, 0);
|
|
||||||
for(var i = idx; i < idx + 4; ++i) {
|
|
||||||
console.log(i + ' = "' + this.textBuffer.asArray()[i] + '"');
|
|
||||||
}
|
|
||||||
this.cursorPos.row = 15;
|
|
||||||
this.cursorPos.col = 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.cursorPos.row = 14;
|
|
||||||
this.cursorPos.col = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.onKeyPress = function(key, isSpecial) {
|
|
||||||
if(isSpecial) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(1 === key.length);
|
|
||||||
|
|
||||||
this.insertCharacterAtCurrentPosition(key);
|
|
||||||
this.updateRenderBuffer();
|
|
||||||
|
|
||||||
// :TODO: is save/restore supported enough? Should we do it ourselves?
|
|
||||||
this.client.term.write(ansi.savePos());
|
|
||||||
// :TODO: Just draw from position onward
|
|
||||||
this.redraw();
|
|
||||||
this.client.term.write(ansi.restorePos());
|
|
||||||
|
|
||||||
|
|
||||||
MultiLineEditTextView.super_.prototype.onKeyPress.call(this, key, isSpecial);
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.onSpecialKeyPress = function(keyName) {
|
|
||||||
if(this.isKeyMapped('up', keyName)) {
|
|
||||||
this.cursorUp();
|
|
||||||
} else if(this.isKeyMapped('down', keyName)) {
|
|
||||||
this.cursorDown();
|
|
||||||
} else if(this.isKeyMapped('left', keyName)) {
|
|
||||||
this.cursorLeft();
|
|
||||||
} else if(this.isKeyMapped('right', keyName)) {
|
|
||||||
this.cursorRight();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
'row=' + this.cursorPos.row + ' / col=' + this.cursorPos.col +
|
|
||||||
' / abs=' + JSON.stringify(this.getAbsolutePosition()) +
|
|
||||||
': ' + this.getCharAtCursorPosition() + '( ' + this.getCharAtCursorPosition().charCodeAt(0) + ')')
|
|
||||||
|
|
||||||
MultiLineEditTextView.super_.prototype.onSpecialKeyPress.call(this, keyName);
|
|
||||||
};
|
|
|
@ -39,6 +39,15 @@ var _ = require('lodash');
|
||||||
// * http://www.jbox.dk/downloads/edit.c
|
// * http://www.jbox.dk/downloads/edit.c
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Misc notes
|
||||||
|
// * See https://github.com/dominictarr/hipster/issues/15 about insert/delete lines
|
||||||
|
//
|
||||||
|
// Blessed
|
||||||
|
// insertLine: CSR(top, bottom) + CUP(y, 0) + IL(1) + CSR(0, height)
|
||||||
|
// deleteLine: CSR(top, bottom) + CUP(y, 0) + DL(1) + CSR(0, height)
|
||||||
|
// Quick Ansi -- update only what was changed:
|
||||||
|
// https://github.com/dominictarr/quickansi
|
||||||
|
|
||||||
//
|
//
|
||||||
// To-Do
|
// To-Do
|
||||||
//
|
//
|
||||||
|
@ -48,6 +57,8 @@ var _ = require('lodash');
|
||||||
// * Some of this shoudl be async'd where there is lots of processing (e.g. word wrap)
|
// * Some of this shoudl be async'd where there is lots of processing (e.g. word wrap)
|
||||||
// * Word wrapping is a bit broke: cannot fill entire self.dimens.width (off by 1-2)
|
// * Word wrapping is a bit broke: cannot fill entire self.dimens.width (off by 1-2)
|
||||||
// * Contigous words will break word wrapping... is not breaking mid word properly
|
// * Contigous words will break word wrapping... is not breaking mid word properly
|
||||||
|
// * Fix backspace when col=0 (e.g. bs to prev line)
|
||||||
|
|
||||||
|
|
||||||
var SPECIAL_KEY_MAP_DEFAULT = {
|
var SPECIAL_KEY_MAP_DEFAULT = {
|
||||||
'line feed' : [ 'return' ],
|
'line feed' : [ 'return' ],
|
||||||
|
@ -67,9 +78,9 @@ var SPECIAL_KEY_MAP_DEFAULT = {
|
||||||
insert : [ 'insert', 'ctrl + v' ],
|
insert : [ 'insert', 'ctrl + v' ],
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.MultiLineEditTextView2 = MultiLineEditTextView2;
|
exports.MultiLineEditTextView = MultiLineEditTextView;
|
||||||
|
|
||||||
function MultiLineEditTextView2(options) {
|
function MultiLineEditTextView(options) {
|
||||||
if(!_.isBoolean(options.acceptsFocus)) {
|
if(!_.isBoolean(options.acceptsFocus)) {
|
||||||
options.acceptsFocus = true;
|
options.acceptsFocus = true;
|
||||||
}
|
}
|
||||||
|
@ -802,7 +813,7 @@ function MultiLineEditTextView2(options) {
|
||||||
//
|
//
|
||||||
// :TODO: apply word wrapping such that text can be re-adjusted if it can now fit on prev
|
// :TODO: apply word wrapping such that text can be re-adjusted if it can now fit on prev
|
||||||
self.keyPressLeft(); // same as hitting left - jump to previous line
|
self.keyPressLeft(); // same as hitting left - jump to previous line
|
||||||
self.keyPressBackspace();
|
//self.keyPressBackspace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -973,28 +984,28 @@ function MultiLineEditTextView2(options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require('util').inherits(MultiLineEditTextView2, View);
|
require('util').inherits(MultiLineEditTextView, View);
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.setWidth = function(width) {
|
MultiLineEditTextView.prototype.setWidth = function(width) {
|
||||||
MultiLineEditTextView2.super_.prototype.setWidth.call(this, width);
|
MultiLineEditTextView.super_.prototype.setWidth.call(this, width);
|
||||||
|
|
||||||
this.calculateTabStops();
|
this.calculateTabStops();
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.redraw = function() {
|
MultiLineEditTextView.prototype.redraw = function() {
|
||||||
MultiLineEditTextView2.super_.prototype.redraw.call(this);
|
MultiLineEditTextView.super_.prototype.redraw.call(this);
|
||||||
|
|
||||||
this.redrawVisibleArea();
|
this.redrawVisibleArea();
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.setFocus = function(focused) {
|
MultiLineEditTextView.prototype.setFocus = function(focused) {
|
||||||
this.client.term.write(this.getSGRFor('text'));
|
this.client.term.write(this.getSGRFor('text'));
|
||||||
this.moveClientCusorToCursorPos();
|
this.moveClientCusorToCursorPos();
|
||||||
|
|
||||||
MultiLineEditTextView2.super_.prototype.setFocus.call(this, focused);
|
MultiLineEditTextView.super_.prototype.setFocus.call(this, focused);
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.setText = function(text) {
|
MultiLineEditTextView.prototype.setText = function(text) {
|
||||||
//this.textLines = [ { text : '' } ];
|
//this.textLines = [ { text : '' } ];
|
||||||
//this.insertRawText('');
|
//this.insertRawText('');
|
||||||
//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!!!";
|
||||||
|
@ -1007,16 +1018,16 @@ MultiLineEditTextView2.prototype.setText = function(text) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.getData = function() {
|
MultiLineEditTextView.prototype.getData = function() {
|
||||||
return this.getOutputText(0, this.textLines.length, true);
|
return this.getOutputText(0, this.textLines.length, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.setPropertyValue = function(propName, value) {
|
MultiLineEditTextView.prototype.setPropertyValue = function(propName, value) {
|
||||||
/* switch(propName) {
|
/* switch(propName) {
|
||||||
case 'text' : this.setText(value); break;
|
case 'text' : this.setText(value); break;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
MultiLineEditTextView2.super_.prototype.setPropertyValue.call(this, propName, value);
|
MultiLineEditTextView.super_.prototype.setPropertyValue.call(this, propName, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
var HANDLED_SPECIAL_KEYS = [
|
var HANDLED_SPECIAL_KEYS = [
|
||||||
|
@ -1030,7 +1041,7 @@ var HANDLED_SPECIAL_KEYS = [
|
||||||
'delete line',
|
'delete line',
|
||||||
];
|
];
|
||||||
|
|
||||||
MultiLineEditTextView2.prototype.onKeyPress = function(ch, key) {
|
MultiLineEditTextView.prototype.onKeyPress = function(ch, key) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var handled;
|
var handled;
|
||||||
|
|
||||||
|
@ -1048,6 +1059,6 @@ MultiLineEditTextView2.prototype.onKeyPress = function(ch, key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!handled) {
|
if(!handled) {
|
||||||
MultiLineEditTextView2.super_.prototype.onKeyPress.call(this, ch, key);
|
MultiLineEditTextView.super_.prototype.onKeyPress.call(this, ch, key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue