From 6bb35042ef6fb19d9af5ee874de9da2816cbc5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Tue, 15 Sep 2015 18:47:26 +0200 Subject: Augmenting the console: - implemented the support of the leftmostCol, the column from which the editing is allowed, - the onInput() handler can return a Promise, which is then waited on to be resolved before further input is allowed, - pasted multi-line content is split into lines, and processed line-by-line as if a single line was pasted multiple times. --- js/codeq/comms.js | 4 +- js/codeq/console.js | 120 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 75 insertions(+), 49 deletions(-) (limited to 'js') diff --git a/js/codeq/comms.js b/js/codeq/comms.js index de6f918..db9b7b5 100644 --- a/js/codeq/comms.js +++ b/js/codeq/comms.js @@ -86,13 +86,13 @@ event = m.event; if (typeof event !== 'string') { - codeq.log.warn('Incoming message without a TID and with no event name, dropping it on the floor: ' + data); + codeq.log.info('Incoming message without a TID and with no event name, dropping it on the floor: ' + data); return; } handlers = requestHandlers[event]; if (!handlers) { - codeq.log.warn('Incoming event message cannot be handled: no handler registered for ' + event); + codeq.log.info('Incoming event message cannot be handled: no handler registered for ' + event); return; } diff --git a/js/codeq/console.js b/js/codeq/console.js index ddf4ce6..41aae40 100644 --- a/js/codeq/console.js +++ b/js/codeq/console.js @@ -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 this.leftmostCol === 'number' && this.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]; -- cgit v1.2.1