From ec61f3acf072a6199d0b248a25ba0b8dd19c8d75 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 May 2017 18:52:06 -0700 Subject: [PATCH] Only trim the right whitespace from selection Fixes #673 --- src/SelectionManager.ts | 41 +++++++++++++++++++++++---------------- src/handlers/Clipboard.ts | 20 ++++++++----------- src/xterm.js | 14 +++++-------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index c8144d4d..7f1665bb 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -113,32 +113,43 @@ export class SelectionManager extends EventEmitter { // Get first row const startRowEndCol = start[1] === end[1] ? end[0] : null; let result: string[] = []; - result.push(this._translateBufferLineToString(this._buffer.get(start[1]), start[0], startRowEndCol)); + result.push(this._translateBufferLineToString(this._buffer.get(start[1]), true, start[0], startRowEndCol)); // Get middle rows for (let i = start[1] + 1; i <= end[1] - 1; i++) { - result.push(this._translateBufferLineToString(this._buffer.get(i))); + result.push(this._translateBufferLineToString(this._buffer.get(i), true)); } // Get final row if (start[1] !== end[1]) { - result.push(this._translateBufferLineToString(this._buffer.get(end[1]), 0, end[1])); + result.push(this._translateBufferLineToString(this._buffer.get(end[1]), true, 0, end[0])); } console.log('selectionText result: ' + result); return result.join('\n'); } - private _translateBufferLineToString(line: any, startCol: number = 0, endCol: number = null): string { + private _translateBufferLineToString(line: any, trimRight: boolean, startCol: number = 0, endCol: number = null): string { // TODO: This function should live in a buffer or buffer line class - endCol = endCol || line.length; - let result = ''; - for (let i = startCol; i < endCol; i++) { - result += line[i][1]; - } - // TODO: Trim line here instead of in handlers/Clipboard? - // TODO: Only trim off the whitespace at the end of a line // TODO: Handle the double-width character case - return result; + + // Get full line + let lineString = ''; + for (let i = 0; i < line.length; i++) { + lineString += line[i][1]; + } + + let finalEndCol = endCol || line.length + + if (trimRight) { + const rightWhitespaceIndex = lineString.search(/\s+$/); + finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex); + // Return the empty string if only trimmed whitespace is selected + if (finalEndCol <= startCol) { + return ''; + } + } + + return lineString.substring(startCol, finalEndCol); } /** @@ -201,8 +212,6 @@ export class SelectionManager extends EventEmitter { * @param event The mousedown event. */ private _onMouseDown(event: MouseEvent) { - // TODO: On right click move the text into the textbox so it can be copied via the context menu - // Only action the primary button if (event.button !== 0) { return; @@ -317,9 +326,7 @@ export class SelectionManager extends EventEmitter { * @param coords The coordinates to get the word at. */ private _selectWordAt(coords: [number, number]): void { - // TODO: Handle double click and drag in both directions! - - const line = this._translateBufferLineToString(this._buffer.get(coords[1])); + const line = this._translateBufferLineToString(this._buffer.get(coords[1]), false); // Expand the string in both directions until a space is hit let startCol = coords[0]; let endCol = coords[0]; diff --git a/src/handlers/Clipboard.ts b/src/handlers/Clipboard.ts index 036a6d8f..02af6cb9 100644 --- a/src/handlers/Clipboard.ts +++ b/src/handlers/Clipboard.ts @@ -16,6 +16,10 @@ interface IWindow extends Window { declare var window: IWindow; +const SPACE_CHAR = String.fromCharCode(32); +const NON_BREAKING_SPACE_CHAR = String.fromCharCode(160); +const ALL_NON_BREAKING_SPACE_REGEX = new RegExp(NON_BREAKING_SPACE_CHAR, 'g'); + /** * Prepares text copied from terminal selection, to be saved in the clipboard by: * 1. stripping all trailing white spaces @@ -24,18 +28,10 @@ declare var window: IWindow; * @returns {string} */ export function prepareTextForClipboard(text: string): string { - let space = String.fromCharCode(32), - nonBreakingSpace = String.fromCharCode(160), - allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'), - processedText = text.split('\n').map(function (line) { - // Strip all trailing white spaces and convert all non-breaking spaces - // to regular spaces. - let processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space); - - return processedLine; - }).join('\n'); - - return processedText; + // TODO: Pass an unjoined string array into this function so not splitting is needed + return text.split('\n').map(line => { + return line.replace(ALL_NON_BREAKING_SPACE_REGEX, SPACE_CHAR); + }).join('\n'); } /** diff --git a/src/xterm.js b/src/xterm.js index d2232300..c9239556 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -521,16 +521,12 @@ Terminal.prototype.initGlobal = function() { Terminal.bindBlur(this); // Bind clipboard functionality - on(this.element, 'copy', function (ev) { - console.log('copy event'); - copyHandler.call(this, ev, term, term.selectionManager); - }); - on(this.textarea, 'paste', function (ev) { - pasteHandler.call(this, ev, term); - }); - on(this.element, 'paste', function (ev) { - pasteHandler.call(this, ev, term); + on(this.element, 'copy', event => { + copyHandler(event, term, term.selectionManager); }); + const pasteHandlerWrapper = event => pasteHandler(event, term); + on(this.textarea, 'paste', pasteHandlerWrapper); + on(this.element, 'paste', pasteHandlerWrapper); if (term.browser.isFirefox) { on(this.element, 'mousedown', event => {