diff options
Diffstat (limited to 'js/codeq/console.js')
-rw-r--r-- | js/codeq/console.js | 122 |
1 files changed, 74 insertions, 48 deletions
diff --git a/js/codeq/console.js b/js/codeq/console.js index ddf4ce6..99c1550 100644 --- a/js/codeq/console.js +++ b/js/codeq/console.js @@ -176,7 +176,7 @@ jq1, jq2, jqCursor; if (!jqLine) { - jqLine = $('<div class="' + lineDescriptor.className + '"></div>'); + jqLine = $('<pre class="cq-con-line ' + lineDescriptor.className + '"></pre>'); if (lineDescriptor.row == 0) { jqContent.prepend(jqLine); } @@ -263,11 +263,12 @@ handler = { 'setLineBuffered': function () { lineBuffered = true; }, 'setNotBuffered': function () { lineBuffered = false; }, - 'onInput': false, // the caller should assign a function here, that takes input as parameter + 'onInput': false, // the caller should assign a function here, that takes input as parameter, and optionally returns a promise which is then waited to be resolved before further input is accepted 'onKeypress': false, // same, but it takes a keycode, and returns a keycode 'inputEnable': function () { inputDisabled = false; }, 'inputDisable': function () { inputDisabled = true; }, 'keyMaps': {}, // will be filled in later + 'leftmostCol': 0, // the column from where editing is possible; it is not possible to delete or change a character to the left of this column 'reflow': function () { var startRow, endRow, i, lineDescriptor; @@ -463,7 +464,8 @@ }, 'moveLeft': function () { - if (currentCol > 0) { + var leftmost = typeof this.leftmostCol === 'number' && this.leftmostCol || 0; + if (currentCol > leftmost) { currentCol--; renderLine(lines[currentRow]); } @@ -479,8 +481,9 @@ 'deleteCharacterLeft': function () { var lineDescriptor = lines[currentRow], - content = lineDescriptor.content; - if ((currentCol > 0) && (currentCol <= content.length)) { + content = lineDescriptor.content, + leftmost = typeof this.leftmostCol === 'number' && this.leftmostCol || 0; + if ((currentCol > leftmost) && (currentCol <= content.length)) { currentCol--; lineDescriptor.content = content.substring(0, currentCol) + content.substring(currentCol + 1); renderLine(lineDescriptor); @@ -547,65 +550,88 @@ } }, + internallyDisabled = false, + handleInput = function (chars) { - var cookedChars = chars, // default - startingRow = currentRow, - dh, i; + var isPastedFromClipboard = clipboardPasteInProgress || !aKeyIsDown, + newLines = chars.split('\n'), + N = newLines.length, + lastLineIndex = N - 1, + i, promise; - if (inputDisabled) { + if (inputDisabled || internallyDisabled) { // flatly ignore clipboardPasteInProgress = false; return; } - // first cook the input - if (typeof handler.onKeypress === 'function') { - try { - cookedChars = handler.onKeypress(chars, clipboardPasteInProgress || !aKeyIsDown); - } - catch (e) { - // TODO: log error - } - } + internallyDisabled = true; + promise = Q(); - if (!cookedChars) { - // nothing to append - clipboardPasteInProgress = false; - return; - } + for (i = 0; i < N; i++) { + promise = promise + .then((function (newLine, lineIndex) {return function () { + var cookedChars = lineIndex < lastLineIndex ? newLine + '\n' : newLine, // default + thisRow = currentRow, + leftmost = typeof handler.leftmostCol === 'number' && handler.leftmostCol || 0, + dh; - // now serve the cooking - handler.insertAtCursor(cookedChars, 'input'); // append what we have to the display - if (typeof handler.onInput === 'function') { // now tell the owner what we've done - if (lineBuffered) { - if (currentRow !== startingRow) { - // in line-buffered mode emit each line separately, except for the last (current) line - for (i = startingRow; i < lines.length; i++) { + // first cook the input + if (typeof handler.onKeypress === 'function') { + // only invoke the handler if the newLine is not an empty string, otherwise cookedChars = '' try { - handler.onInput(lines[i].content); + cookedChars = cookedChars && handler.onKeypress(cookedChars, isPastedFromClipboard); } catch (e) { - // TODO: log error + codeq.log.error('Error during invocation of terminal onKeypress: ' + e, e); } } - } - } - else { - try { - handler.onInput(cookedChars); - } - catch (e) { - // TODO: log error - } - } + + if (!cookedChars) { + // nothing to append + return; + } + + // now serve the cooking + handler.insertAtCursor(cookedChars, 'input'); // append what we have to the display + // scroll to bottom on input + dh = jqContent.height() - jqElt.height(); + if (dh > 0) + jqElt.scrollTop(dh); + + if (typeof handler.onInput === 'function') { // now tell the owner what we've done + if (lineBuffered) { + if (thisRow < currentRow) { + // in line-buffered mode emit each line separately, except for the last (current) line + try { + return handler.onInput(lines[thisRow].content.substring(leftmost)); + } + catch (e) { + codeq.log.error('Error while invoking terminal onInput: ' + e, e); + } + } + } + else if (cookedChars) { + try { + return handler.onInput(cookedChars); + } + catch (e) { + codeq.log.error('Error while invoking terminal onInput: ' + e, e); + } + } + } + + };})(newLines[i], i)) + .fail(function (e) { + codeq.log.error('Error in handleInput loop: ' + e, e); + }); } - clipboardPasteInProgress = false; + promise.fin(function () { + internallyDisabled = false; + }).done(); - // scroll to bottom on input - dh = jqContent.height() - jqElt.height(); - if (dh > 0) - jqElt.scrollTop(dh); + clipboardPasteInProgress = false; }, clipboardPasteInProgress = false, // whether the previous keydown was a CTRL+V or shift+insert @@ -646,7 +672,7 @@ jqInput.on('keydown', function (evt) { var modifiers = ['' + (0 + evt.shiftKey), '' + (0 + (evt.ctrlKey || evt.metaKey)), '' + (0 + evt.altKey)].join(''), handlersForModifiers = handler.keyMaps[modifiers], - acceptKeydown = !inputDisabled, // the default value + acceptKeydown = !(inputDisabled || internallyDisabled), // the default value eventInfo = processKeyboardEvent(evt), handlerForKeydown = handlersForModifiers && handlersForModifiers[eventInfo.code]; |