From 8d12881a1cd9f8f88160f6b7686c9db446a92dbc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 12 Jun 2017 16:27:13 -0700 Subject: [PATCH 01/19] Very basic find implementation Part of #553 --- src/Interfaces.ts | 3 ++ src/SearchHelper.ts | 75 +++++++++++++++++++++++++++++++++++++++++ src/SelectionManager.ts | 9 +++++ src/xterm.js | 3 ++ 4 files changed, 90 insertions(+) create mode 100644 src/SearchHelper.ts diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 4b8576742d..5016b4f6f3 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -21,6 +21,7 @@ export interface ITerminal { element: HTMLElement; rowContainer: HTMLElement; selectionContainer: HTMLElement; + selectionManager: ISelectionManager; charMeasure: ICharMeasure; textarea: HTMLTextAreaElement; ybase: number; @@ -51,6 +52,8 @@ export interface ITerminal { export interface ISelectionManager { selectionText: string; + + setSelection(row: number, col: number, length: number); } export interface ICharMeasure { diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts new file mode 100644 index 0000000000..f5021076e0 --- /dev/null +++ b/src/SearchHelper.ts @@ -0,0 +1,75 @@ +import { ITerminal } from './Interfaces'; + +export class SearchHelper { + constructor(private _terminal: ITerminal) { + + } + + /** + * Find the next instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + */ + public findNext(term: string): void { + if (!term || term.length === 0) { + return; + } + // TODO: Return number of results? + + for (let currentLine = this._terminal.ydisp; currentLine < this._terminal.ybase + this._terminal.rows; currentLine++) { + const bufferLine = this._terminal.lines.get(currentLine); + const stringLine = this._translateBufferLineToString(bufferLine, true); + const searchIndex = stringLine.indexOf(term); + if (searchIndex >= 0) { + console.log('found term on line: ' + currentLine); + console.log(stringLine); + this._terminal.selectionManager.setSelection(searchIndex, currentLine, term.length); + break; + } + } + } + + // TODO: Consolidate with SelectionManager function + 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 + + // TODO: Move these constants elsewhere, they belong in a buffer or buffer + // data/line class. + const LINE_DATA_CHAR_INDEX = 1; + const LINE_DATA_WIDTH_INDEX = 2; + // Get full line + let lineString = ''; + let widthAdjustedStartCol = startCol; + let widthAdjustedEndCol = endCol; + for (let i = 0; i < line.length; i++) { + const char = line[i]; + lineString += char[LINE_DATA_CHAR_INDEX]; + // Adjust start and end cols for wide characters if they affect their + // column indexes + if (char[LINE_DATA_WIDTH_INDEX] === 0) { + if (startCol >= i) { + widthAdjustedStartCol--; + } + if (endCol >= i) { + widthAdjustedEndCol--; + } + } + } + + // Calculate the final end col by trimming whitespace on the right of the + // line if needed. + let finalEndCol = widthAdjustedEndCol || line.length; + if (trimRight) { + const rightWhitespaceIndex = lineString.search(/\s+$/); + if (rightWhitespaceIndex !== -1) { + finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex); + } + // Return the empty string if only trimmed whitespace is selected + if (finalEndCol <= widthAdjustedStartCol) { + return ''; + } + } + + return lineString.substring(widthAdjustedStartCol, finalEndCol); + } +} diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 906d5b0139..3c3b839fb4 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -551,6 +551,15 @@ export class SelectionManager extends EventEmitter { return charIndex; } + public setSelection(col: number, row: number, length: number): void { + this._model.clearSelection(); + this._removeMouseDownListeners(); + console.log('setSelection', arguments); + this._model.selectionStart = [col, row]; + this._model.selectionStartLength = length; + this.refresh(); + } + /** * Selects the word at the coordinates specified. Words are defined as all * non-whitespace characters. diff --git a/src/xterm.js b/src/xterm.js index a476fd7eb0..789a7adff6 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -21,6 +21,7 @@ import { Parser } from './Parser'; import { Renderer } from './Renderer'; import { Linkifier } from './Linkifier'; import { SelectionManager } from './SelectionManager'; +import { SearchHelper } from './SearchHelper'; import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; import * as Mouse from './utils/Mouse'; @@ -223,6 +224,7 @@ function Terminal(options) { this.renderer = this.renderer || null; this.selectionManager = this.selectionManager || null; this.linkifier = this.linkifier || new Linkifier(); + this.searchHelper = this.searchHelper || null; // user input states this.writeBuffer = []; @@ -706,6 +708,7 @@ Terminal.prototype.open = function(parent, focus) { this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end)); this.on('scroll', () => this.selectionManager.refresh()); this.viewportElement.addEventListener('scroll', () => this.selectionManager.refresh()); + this.searchHelper = new SearchHelper(this);; // Setup loop that draws to screen this.refresh(0, this.rows - 1); From 280b698a5001754db2d132a909ecfeb276584551 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 12 Jun 2017 21:59:46 -0700 Subject: [PATCH 02/19] More work on findNext --- src/Interfaces.ts | 2 ++ src/SearchHelper.ts | 65 ++++++++++++++++++++++++++++++++++------- src/SelectionManager.ts | 3 ++ 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 5016b4f6f3..4de2f28582 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -52,6 +52,8 @@ export interface ITerminal { export interface ISelectionManager { selectionText: string; + selectionStart: [number, number]; + selectionEnd: [number, number]; setSelection(row: number, col: number, length: number); } diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index f5021076e0..9b2f07b675 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -1,32 +1,77 @@ import { ITerminal } from './Interfaces'; +interface ISearchResult { + term: string; + col: number; + row: number; +} + export class SearchHelper { constructor(private _terminal: ITerminal) { - } /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. * @param term The term to search for. + * @return Whether a result was found. */ - public findNext(term: string): void { + public findNext(term: string): boolean { if (!term || term.length === 0) { return; } // TODO: Return number of results? - for (let currentLine = this._terminal.ydisp; currentLine < this._terminal.ybase + this._terminal.rows; currentLine++) { - const bufferLine = this._terminal.lines.get(currentLine); - const stringLine = this._translateBufferLineToString(bufferLine, true); - const searchIndex = stringLine.indexOf(term); - if (searchIndex >= 0) { - console.log('found term on line: ' + currentLine); - console.log(stringLine); - this._terminal.selectionManager.setSelection(searchIndex, currentLine, term.length); + let result: ISearchResult; + + let startRow = this._terminal.ydisp; + if (this._terminal.selectionManager.selectionEnd) { + // Start from the selection end if there is a selection + startRow = this._terminal.selectionManager.selectionEnd[1]; + } + + // Search from ydisp + 1 to end + for (let y = startRow + 1; y < this._terminal.ybase + this._terminal.rows; y++) { + result = this._findInLine(term, y); + if (result) { break; } } + + // Search from the top to the current ydisp + if (!result) { + for (let y = 0; y < startRow; y++) { + result = this._findInLine(term, y); + if (result) { + break; + } + } + } + + // Set selection and scroll if a result was found + return this._selectResult(result); + } + + private _findInLine(term: string, y: number): ISearchResult { + const bufferLine = this._terminal.lines.get(y); + const stringLine = this._translateBufferLineToString(bufferLine, true); + const searchIndex = stringLine.indexOf(term); + if (searchIndex >= 0) { + return { + term, + col: searchIndex, + row: y + }; + } + } + + private _selectResult(result: ISearchResult): boolean { + if (!result) { + return; + } + this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length); + const scrollAmount = Math.max(Math.min(result.row - this._terminal.ydisp, this._terminal.ybase), 0); + this._terminal.scrollDisp(scrollAmount, false); } // TODO: Consolidate with SelectionManager function diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 3c3b839fb4..14a0f5a34c 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -156,6 +156,9 @@ export class SelectionManager extends EventEmitter { this._buffer = buffer; } + public get selectionStart(): [number, number] { return this._model.finalSelectionStart; } + public get selectionEnd(): [number, number] { return this._model.finalSelectionEnd; } + /** * Gets whether there is an active text selection. */ From d3f5a0651717c33e22bb3200d53f6b7889463d8a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 13 Jun 2017 19:34:25 -0700 Subject: [PATCH 03/19] Fix search scrolling up --- src/SearchHelper.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index 9b2f07b675..5c90a96628 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -70,8 +70,7 @@ export class SearchHelper { return; } this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length); - const scrollAmount = Math.max(Math.min(result.row - this._terminal.ydisp, this._terminal.ybase), 0); - this._terminal.scrollDisp(scrollAmount, false); + this._terminal.scrollDisp(result.row - this._terminal.ydisp, false); } // TODO: Consolidate with SelectionManager function From 7d8f698096649120b31e601332811be7868770b4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 13 Jun 2017 19:43:18 -0700 Subject: [PATCH 04/19] Add findPrevious --- src/SearchHelper.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index 5c90a96628..4a8631d10b 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -8,6 +8,10 @@ interface ISearchResult { export class SearchHelper { constructor(private _terminal: ITerminal) { + // TODO: Search for multiple instances on 1 line + // TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted + // TODO: Highlight other instances in the viewport + // TODO: Support regex, case sensitivity, etc. } /** @@ -20,7 +24,6 @@ export class SearchHelper { if (!term || term.length === 0) { return; } - // TODO: Return number of results? let result: ISearchResult; @@ -52,6 +55,47 @@ export class SearchHelper { return this._selectResult(result); } + /** + * Find the previous instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ + public findPrevious(term: string): boolean { + if (!term || term.length === 0) { + return; + } + + let result: ISearchResult; + + let startRow = this._terminal.ydisp; + if (this._terminal.selectionManager.selectionStart) { + // Start from the selection end if there is a selection + startRow = this._terminal.selectionManager.selectionStart[1]; + } + + // Search from ydisp + 1 to end + for (let y = startRow - 1; y >= 0; y--) { + result = this._findInLine(term, y); + if (result) { + break; + } + } + + // Search from the top to the current ydisp + if (!result) { + for (let y = this._terminal.ybase + this._terminal.rows - 1; y > startRow; y--) { + result = this._findInLine(term, y); + if (result) { + break; + } + } + } + + // Set selection and scroll if a result was found + return this._selectResult(result); + } + private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); const stringLine = this._translateBufferLineToString(bufferLine, true); From f88dcd160c8857464c3bcf8f84d15f4440a02e19 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 13 Jun 2017 19:49:12 -0700 Subject: [PATCH 05/19] Expose API on Terminal --- src/SearchHelper.ts | 7 ++++--- src/xterm.js | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index 4a8631d10b..65d82ecc5e 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -22,7 +22,7 @@ export class SearchHelper { */ public findNext(term: string): boolean { if (!term || term.length === 0) { - return; + return false; } let result: ISearchResult; @@ -63,7 +63,7 @@ export class SearchHelper { */ public findPrevious(term: string): boolean { if (!term || term.length === 0) { - return; + return false; } let result: ISearchResult; @@ -111,10 +111,11 @@ export class SearchHelper { private _selectResult(result: ISearchResult): boolean { if (!result) { - return; + return false; } this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length); this._terminal.scrollDisp(result.row - this._terminal.ydisp, false); + return true; } // TODO: Consolidate with SelectionManager function diff --git a/src/xterm.js b/src/xterm.js index 789a7adff6..8f2d64e3f7 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -1405,6 +1405,26 @@ Terminal.prototype.selectAll = function() { this.selectionManager.selectAll(); } +/** + * Find the next instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ +Terminal.prototype.findNext = function(term) { + return this.searchHelper.findNext(term); +} + +/** + * Find the previous instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ +Terminal.prototype.findPrevious = function(term) { + return this.searchHelper.findPrevious(term); +} + /** * Handle a keydown event * Key Resources: From b957130787e6aa2d86f1d41566307abd0b8fac60 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 13 Jun 2017 19:55:29 -0700 Subject: [PATCH 06/19] Consolidate translateBufferLineToString functions --- src/SearchHelper.ts | 51 +++++------------------------------- src/SelectionManager.ts | 58 ++++------------------------------------- src/utils/BufferLine.ts | 55 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 98 deletions(-) create mode 100644 src/utils/BufferLine.ts diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index 65d82ecc5e..5766848e8f 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -1,4 +1,9 @@ +/** + * @license MIT + */ + import { ITerminal } from './Interfaces'; +import { translateBufferLineToString } from './utils/BufferLine'; interface ISearchResult { term: string; @@ -98,7 +103,7 @@ export class SearchHelper { private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); - const stringLine = this._translateBufferLineToString(bufferLine, true); + const stringLine = translateBufferLineToString(bufferLine, true); const searchIndex = stringLine.indexOf(term); if (searchIndex >= 0) { return { @@ -117,48 +122,4 @@ export class SearchHelper { this._terminal.scrollDisp(result.row - this._terminal.ydisp, false); return true; } - - // TODO: Consolidate with SelectionManager function - 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 - - // TODO: Move these constants elsewhere, they belong in a buffer or buffer - // data/line class. - const LINE_DATA_CHAR_INDEX = 1; - const LINE_DATA_WIDTH_INDEX = 2; - // Get full line - let lineString = ''; - let widthAdjustedStartCol = startCol; - let widthAdjustedEndCol = endCol; - for (let i = 0; i < line.length; i++) { - const char = line[i]; - lineString += char[LINE_DATA_CHAR_INDEX]; - // Adjust start and end cols for wide characters if they affect their - // column indexes - if (char[LINE_DATA_WIDTH_INDEX] === 0) { - if (startCol >= i) { - widthAdjustedStartCol--; - } - if (endCol >= i) { - widthAdjustedEndCol--; - } - } - } - - // Calculate the final end col by trimming whitespace on the right of the - // line if needed. - let finalEndCol = widthAdjustedEndCol || line.length; - if (trimRight) { - const rightWhitespaceIndex = lineString.search(/\s+$/); - if (rightWhitespaceIndex !== -1) { - finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex); - } - // Return the empty string if only trimmed whitespace is selected - if (finalEndCol <= widthAdjustedStartCol) { - return ''; - } - } - - return lineString.substring(widthAdjustedStartCol, finalEndCol); - } } diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 14a0f5a34c..e2ba3756ed 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -8,6 +8,7 @@ import { EventEmitter } from './EventEmitter'; import * as Mouse from './utils/Mouse'; import { ITerminal } from './Interfaces'; import { SelectionModel } from './SelectionModel'; +import { translateBufferLineToString } from './utils/BufferLine'; /** * The number of pixels the mouse needs to be above or below the viewport in @@ -179,16 +180,16 @@ 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]), true, start[0], startRowEndCol)); + result.push(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), true)); + result.push(translateBufferLineToString(this._buffer.get(i), true)); } // Get final row if (start[1] !== end[1]) { - result.push(this._translateBufferLineToString(this._buffer.get(end[1]), true, 0, end[0])); + result.push(translateBufferLineToString(this._buffer.get(end[1]), true, 0, end[0])); } // Format string by replacing non-breaking space chars with regular spaces @@ -209,55 +210,6 @@ export class SelectionManager extends EventEmitter { this.refresh(); } - /** - * Translates a buffer line to a string, with optional start and end columns. - * Wide characters will count as two columns in the resulting string. This - * function is useful for getting the actual text underneath the raw selection - * position. - * @param line The line being translated. - * @param trimRight Whether to trim whitespace to the right. - * @param startCol The column to start at. - * @param endCol The column to end at. - */ - 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 - - // Get full line - let lineString = ''; - let widthAdjustedStartCol = startCol; - let widthAdjustedEndCol = endCol; - for (let i = 0; i < line.length; i++) { - const char = line[i]; - lineString += char[LINE_DATA_CHAR_INDEX]; - // Adjust start and end cols for wide characters if they affect their - // column indexes - if (char[LINE_DATA_WIDTH_INDEX] === 0) { - if (startCol >= i) { - widthAdjustedStartCol--; - } - if (endCol >= i) { - widthAdjustedEndCol--; - } - } - } - - // Calculate the final end col by trimming whitespace on the right of the - // line if needed. - let finalEndCol = widthAdjustedEndCol || line.length; - if (trimRight) { - const rightWhitespaceIndex = lineString.search(/\s+$/); - if (rightWhitespaceIndex !== -1) { - finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex); - } - // Return the empty string if only trimmed whitespace is selected - if (finalEndCol <= widthAdjustedStartCol) { - return ''; - } - } - - return lineString.substring(widthAdjustedStartCol, finalEndCol); - } - /** * Queues a refresh, redrawing the selection on the next opportunity. */ @@ -570,7 +522,7 @@ export class SelectionManager extends EventEmitter { */ protected _selectWordAt(coords: [number, number]): void { const bufferLine = this._buffer.get(coords[1]); - const line = this._translateBufferLineToString(bufferLine, false); + const line = translateBufferLineToString(bufferLine, false); // Get actual index, taking into consideration wide characters let endIndex = this._convertViewportColToCharacterIndex(bufferLine, coords); diff --git a/src/utils/BufferLine.ts b/src/utils/BufferLine.ts new file mode 100644 index 0000000000..3dc6525ad3 --- /dev/null +++ b/src/utils/BufferLine.ts @@ -0,0 +1,55 @@ +/** + * @license MIT + */ + +// TODO: This module should be merged into a buffer or buffer line class + +const LINE_DATA_CHAR_INDEX = 1; +const LINE_DATA_WIDTH_INDEX = 2; + +/** + * Translates a buffer line to a string, with optional start and end columns. + * Wide characters will count as two columns in the resulting string. This + * function is useful for getting the actual text underneath the raw selection + * position. + * @param line The line being translated. + * @param trimRight Whether to trim whitespace to the right. + * @param startCol The column to start at. + * @param endCol The column to end at. + */ +export function translateBufferLineToString(line: any, trimRight: boolean, startCol: number = 0, endCol: number = null): string { + // Get full line + let lineString = ''; + let widthAdjustedStartCol = startCol; + let widthAdjustedEndCol = endCol; + for (let i = 0; i < line.length; i++) { + const char = line[i]; + lineString += char[LINE_DATA_CHAR_INDEX]; + // Adjust start and end cols for wide characters if they affect their + // column indexes + if (char[LINE_DATA_WIDTH_INDEX] === 0) { + if (startCol >= i) { + widthAdjustedStartCol--; + } + if (endCol >= i) { + widthAdjustedEndCol--; + } + } + } + + // Calculate the final end col by trimming whitespace on the right of the + // line if needed. + let finalEndCol = widthAdjustedEndCol || line.length; + if (trimRight) { + const rightWhitespaceIndex = lineString.search(/\s+$/); + if (rightWhitespaceIndex !== -1) { + finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex); + } + // Return the empty string if only trimmed whitespace is selected + if (finalEndCol <= widthAdjustedStartCol) { + return ''; + } + } + + return lineString.substring(widthAdjustedStartCol, finalEndCol); +} From 528f06bc62502cb60245954f184a96b88a74b89d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 13 Jun 2017 20:03:29 -0700 Subject: [PATCH 07/19] Remove log --- src/SelectionManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 930f09d1bc..f027e4a3f7 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -524,7 +524,6 @@ export class SelectionManager extends EventEmitter { public setSelection(col: number, row: number, length: number): void { this._model.clearSelection(); this._removeMouseDownListeners(); - console.log('setSelection', arguments); this._model.selectionStart = [col, row]; this._model.selectionStartLength = length; this.refresh(); From 6854def13c6d88bf5c17579a2fc5c882d84184f3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 20 Jun 2017 17:40:31 -0700 Subject: [PATCH 08/19] Use case-insensitive search by default --- src/SearchHelper.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SearchHelper.ts b/src/SearchHelper.ts index 5766848e8f..300daef6c2 100644 --- a/src/SearchHelper.ts +++ b/src/SearchHelper.ts @@ -103,8 +103,9 @@ export class SearchHelper { private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); - const stringLine = translateBufferLineToString(bufferLine, true); - const searchIndex = stringLine.indexOf(term); + const lowerStringLine = translateBufferLineToString(bufferLine, true).toLowerCase(); + const lowerTerm = term.toLowerCase(); + const searchIndex = lowerStringLine.indexOf(lowerTerm); if (searchIndex >= 0) { return { term, From 19381454ad959c53915e0393eac8c66047ce7a3b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 22 Jun 2017 19:36:53 -0700 Subject: [PATCH 09/19] Get find working as an addon --- demo/index.html | 1 + gulpfile.js | 29 ++++++++-- src/addons/search/search.ts | 56 +++++++++++++++++++ .../search/searchHelper.ts} | 8 +-- src/addons/search/tsconfig.json | 10 ++++ src/xterm.js | 25 +-------- 6 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 src/addons/search/search.ts rename src/{SearchHelper.ts => addons/search/searchHelper.ts} (91%) create mode 100644 src/addons/search/tsconfig.json diff --git a/demo/index.html b/demo/index.html index d4574aa3b2..9546b69781 100644 --- a/demo/index.html +++ b/demo/index.html @@ -10,6 +10,7 @@ +

xterm.js: xterm, in the browser

diff --git a/gulpfile.js b/gulpfile.js index 1f92e53751..1dd49887fc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,7 @@ const ts = require('gulp-typescript'); let buildDir = process.env.BUILD_DIR || 'build'; let tsProject = ts.createProject('tsconfig.json'); +let tsProjectSearchAddon = ts.createProject('./src/addons/search/tsconfig.json'); let srcDir = tsProject.config.compilerOptions.rootDir; let outDir = tsProject.config.compilerOptions.outDir; @@ -30,13 +31,18 @@ gulp.task('tsc', function () { let tsResult = tsProject.src().pipe(sourcemaps.init()).pipe(tsProject()); let tsc = tsResult.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir)); + fs.emptyDirSync(`${outDir}/addons`); + fs.emptyDirSync(`${outDir}/addons/search`); + let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon()); + let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`)); + // Copy all addons from ${srcDir}/ to ${outDir}/ - let copyAddons = gulp.src(`${srcDir}/addons/**/*`).pipe(gulp.dest(`${outDir}/addons`)); + let copyAddons = gulp.src([`${srcDir}/addons/**/*`, `!${srcDir}/addons/search`, `!${srcDir}/addons/search/**`]).pipe(gulp.dest(`${outDir}/addons`)); // Copy stylesheets from ${srcDir}/ to ${outDir}/ let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir)); - return merge(tsc, copyAddons, copyStylesheets); + return merge(tsc, tscSearchAddon, copyAddons, copyStylesheets); }); /** @@ -63,13 +69,28 @@ gulp.task('browserify', ['tsc'], function() { .pipe(sourcemaps.write('./')) .pipe(gulp.dest(buildDir)); + let browserifyOptionsSearchAddon = { + basedir: buildDir, + debug: true, + entries: [`../${outDir}/addons/search/search.js`], + cache: {}, + packageCache: {} + }; + let bundleStreamSearchAddon = browserify(browserifyOptionsSearchAddon) + .bundle() + .pipe(source('./addons/search/search.js')) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'})) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(buildDir)); + // Copy all add-ons from ${outDir}/ to buildDir - let copyAddons = gulp.src(`${outDir}/addons/**/*`).pipe(gulp.dest(`${buildDir}/addons`)); + let copyAddons = gulp.src([`${outDir}/addons/**/*`, `!${outDir}/addons/search`, `!${outDir}/addons/search/**`]).pipe(gulp.dest(`${buildDir}/addons`)); // Copy stylesheets from ${outDir}/ to ${buildDir}/ let copyStylesheets = gulp.src(`${outDir}/**/*.css`).pipe(gulp.dest(buildDir)); - return merge(bundleStream, copyAddons, copyStylesheets); + return merge(bundleStream, bundleStreamSearchAddon, copyAddons, copyStylesheets); }); gulp.task('instrument-test', function () { diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts new file mode 100644 index 0000000000..b049eba7df --- /dev/null +++ b/src/addons/search/search.ts @@ -0,0 +1,56 @@ +/** + * @license MIT + */ + +import { SearchHelper } from './SearchHelper'; + +declare var exports: any; +declare var module: any; +declare var define: any; +declare var require: any; + +(function (addon) { + if ('Terminal' in window) { + /* + * Plain browser environment + */ + addon((window).Terminal); + } else if (typeof define == 'function') { + /* + * Require.js is available + */ + define(['../../xterm'], addon); + } else if (typeof exports === 'object' && typeof module === 'object') { + /* + * CommonJS environment + */ + var xterm = '../../xterm'; // Put in a variable do it's not pulled in by browserify + module.exports = addon(require(xterm)); + } +})((Terminal: any) => { + /** + * Find the next instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ + Terminal.prototype.findNext = function(term: string): boolean { + if (!this._searchHelper) { + this.searchHelper = new SearchHelper(this, Terminal.translateBufferLineToString); + } + return (this.searchHelper).findNext(term); + }; + + /** + * Find the previous instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The term to search for. + * @return Whether a result was found. + */ + Terminal.prototype.findPrevious = function(term: string): boolean { + if (!this._searchHelper) { + this.searchHelper = new SearchHelper(this, Terminal.translateBufferLineToString); + } + return (this.searchHelper).findPrevious(term); + }; +}); diff --git a/src/SearchHelper.ts b/src/addons/search/searchHelper.ts similarity index 91% rename from src/SearchHelper.ts rename to src/addons/search/searchHelper.ts index 300daef6c2..6f88e04b91 100644 --- a/src/SearchHelper.ts +++ b/src/addons/search/searchHelper.ts @@ -2,8 +2,8 @@ * @license MIT */ -import { ITerminal } from './Interfaces'; -import { translateBufferLineToString } from './utils/BufferLine'; +// import { ITerminal } from '../../Interfaces'; +// import { translateBufferLineToString } from '../../utils/BufferLine'; interface ISearchResult { term: string; @@ -12,7 +12,7 @@ interface ISearchResult { } export class SearchHelper { - constructor(private _terminal: ITerminal) { + constructor(private _terminal: any, private _translateBufferLineToString: any) { // TODO: Search for multiple instances on 1 line // TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted // TODO: Highlight other instances in the viewport @@ -103,7 +103,7 @@ export class SearchHelper { private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); - const lowerStringLine = translateBufferLineToString(bufferLine, true).toLowerCase(); + const lowerStringLine = this._translateBufferLineToString(bufferLine, true).toLowerCase(); const lowerTerm = term.toLowerCase(); const searchIndex = lowerStringLine.indexOf(lowerTerm); if (searchIndex >= 0) { diff --git a/src/addons/search/tsconfig.json b/src/addons/search/tsconfig.json new file mode 100644 index 0000000000..f20bdf3d42 --- /dev/null +++ b/src/addons/search/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "rootDir": ".", + "outDir": "./c", + "sourceMap": true, + "removeComments": true + } +} diff --git a/src/xterm.js b/src/xterm.js index b485069ae5..dc57cc211c 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -21,12 +21,12 @@ import { Parser } from './Parser'; import { Renderer } from './Renderer'; import { Linkifier } from './Linkifier'; import { SelectionManager } from './SelectionManager'; -import { SearchHelper } from './SearchHelper'; import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; import * as Mouse from './utils/Mouse'; import { CHARSETS } from './Charsets'; import { getRawByteCoords } from './utils/Mouse'; +import { translateBufferLineToString } from './utils/BufferLine'; /** * Terminal Emulation References: @@ -224,7 +224,6 @@ function Terminal(options) { this.renderer = this.renderer || null; this.selectionManager = this.selectionManager || null; this.linkifier = this.linkifier || new Linkifier(); - this.searchHelper = this.searchHelper || null; // user input states this.writeBuffer = []; @@ -708,7 +707,6 @@ Terminal.prototype.open = function(parent, focus) { this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end)); this.on('scroll', () => this.selectionManager.refresh()); this.viewportElement.addEventListener('scroll', () => this.selectionManager.refresh()); - this.searchHelper = new SearchHelper(this);; // Setup loop that draws to screen this.refresh(0, this.rows - 1); @@ -1408,26 +1406,6 @@ Terminal.prototype.selectAll = function() { this.selectionManager.selectAll(); } -/** - * Find the next instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The term to search for. - * @return Whether a result was found. - */ -Terminal.prototype.findNext = function(term) { - return this.searchHelper.findNext(term); -} - -/** - * Find the previous instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The term to search for. - * @return Whether a result was found. - */ -Terminal.prototype.findPrevious = function(term) { - return this.searchHelper.findPrevious(term); -} - /** * Handle a keydown event * Key Resources: @@ -2408,6 +2386,7 @@ function keys(obj) { * Expose */ +Terminal.translateBufferLineToString = translateBufferLineToString; Terminal.EventEmitter = EventEmitter; Terminal.inherits = inherits; From 7f5e72dbdb104c368d6b1d587cbd4f04f8e6cbd8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 5 Jul 2017 13:06:10 -0700 Subject: [PATCH 10/19] Ensure scroll bar is refreshed after erase all in display Fixes #760 --- src/InputHandler.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 34131a15a1..368a82b821 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -392,6 +392,8 @@ export class InputHandler implements IInputHandler { this._terminal.lines.trimStart(scrollBackSize); this._terminal.ybase = Math.max(this._terminal.ybase - scrollBackSize, 0); this._terminal.ydisp = Math.max(this._terminal.ydisp - scrollBackSize, 0); + // Force a scroll event to refresh viewport + this._terminal.scrollDisp(0); } break; } From 729f646a280972d82c240a0f7683027461dac301 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 6 Jul 2017 22:28:33 -0700 Subject: [PATCH 11/19] Use emit directly due to #766 --- src/InputHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 368a82b821..43958717f0 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -393,7 +393,7 @@ export class InputHandler implements IInputHandler { this._terminal.ybase = Math.max(this._terminal.ybase - scrollBackSize, 0); this._terminal.ydisp = Math.max(this._terminal.ydisp - scrollBackSize, 0); // Force a scroll event to refresh viewport - this._terminal.scrollDisp(0); + this._terminal.emit('scroll', 0); } break; } From 80f7a371184ea0876860848746f0058bb4edaf4e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jul 2017 23:13:41 -0700 Subject: [PATCH 12/19] Point to search addon properly --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index 48bf9df9f1..ead39327f5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -72,7 +72,7 @@ gulp.task('browserify', ['tsc'], function() { let browserifyOptionsSearchAddon = { basedir: buildDir, debug: true, - entries: [`../${outDir}/addons/search/search.js`], + entries: [`${outDir}/addons/search/search.js`], cache: {}, packageCache: {} }; From 3c0e142f73e0e8d4c5978c3ec915da445cdb5697 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jul 2017 23:53:16 -0700 Subject: [PATCH 13/19] Fix sourcemaps --- gulpfile.js | 43 ++++++++++++++++++++++++--------- src/addons/search/tsconfig.json | 2 +- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index ead39327f5..9b0a6de73f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,7 @@ +/** + * @license MIT + */ + const browserify = require('browserify'); const buffer = require('vinyl-buffer'); const coveralls = require('gulp-coveralls'); @@ -31,7 +35,6 @@ gulp.task('tsc', function () { let tsResult = tsProject.src().pipe(sourcemaps.init()).pipe(tsProject()); let tsc = tsResult.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir)); - fs.emptyDirSync(`${outDir}/addons`); fs.emptyDirSync(`${outDir}/addons/search`); let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon()); let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`)); @@ -69,28 +72,38 @@ gulp.task('browserify', ['tsc'], function() { .pipe(sourcemaps.write('./')) .pipe(gulp.dest(buildDir)); - let browserifyOptionsSearchAddon = { - basedir: buildDir, + // Copy stylesheets from ${outDir}/ to ${buildDir}/ + let copyStylesheets = gulp.src(`${outDir}/**/*.css`).pipe(gulp.dest(buildDir)); + + return merge(bundleStream, copyStylesheets); +}); + +gulp.task('browserify-addons', ['tsc'], function() { + let searchOptions = { + basedir: `${buildDir}/addons/search`, debug: true, entries: [`${outDir}/addons/search/search.js`], cache: {}, packageCache: {} }; - let bundleStreamSearchAddon = browserify(browserifyOptionsSearchAddon) + let searchBundle = browserify(searchOptions) .bundle() .pipe(source('./addons/search/search.js')) .pipe(buffer()) - .pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'})) + .pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''})) .pipe(sourcemaps.write('./')) .pipe(gulp.dest(buildDir)); - // Copy all add-ons from ${outDir}/ to buildDir - let copyAddons = gulp.src([`${outDir}/addons/**/*`, `!${outDir}/addons/search`, `!${outDir}/addons/search/**`]).pipe(gulp.dest(`${buildDir}/addons`)); - - // Copy stylesheets from ${outDir}/ to ${buildDir}/ - let copyStylesheets = gulp.src(`${outDir}/**/*.css`).pipe(gulp.dest(buildDir)); + // Copy all add-ons from outDir to buildDir + let copyAddons = gulp.src([ + // Copy JS addons + `${outDir}/addons/**/*`, + // Exclude TS addons from copy as they are being built via browserify + `!${outDir}/addons/search`, + `!${outDir}/addons/search/**` + ]).pipe(gulp.dest(`${buildDir}/addons`)); - return merge(bundleStream, bundleStreamSearchAddon, copyAddons, copyStylesheets); + return merge(searchBundle, copyAddons); }); gulp.task('instrument-test', function () { @@ -119,6 +132,12 @@ gulp.task('sorcery', ['browserify'], function () { chain.writeSync(); }); +gulp.task('sorcery-addons', ['browserify-addons'], function () { + var chain = sorcery.loadSync(`${buildDir}/addons/search/search.js`); + chain.apply(); + chain.writeSync(); +}); + /** * Submit coverage results to coveralls.io */ @@ -127,6 +146,6 @@ gulp.task('coveralls', function () { .pipe(coveralls()); }); -gulp.task('build', ['sorcery']); +gulp.task('build', ['sorcery', 'sorcery-addons']); gulp.task('test', ['mocha']); gulp.task('default', ['build']); diff --git a/src/addons/search/tsconfig.json b/src/addons/search/tsconfig.json index f20bdf3d42..7f72e47fdb 100644 --- a/src/addons/search/tsconfig.json +++ b/src/addons/search/tsconfig.json @@ -3,7 +3,7 @@ "module": "commonjs", "target": "es5", "rootDir": ".", - "outDir": "./c", + "outDir": "../../../lib/addons/search/", "sourceMap": true, "removeComments": true } From fab039ddf3ce5f07ea9df7fd8a61e3f896cf9c42 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 00:26:33 -0700 Subject: [PATCH 14/19] Rearrange module loader to work with browserify --- src/addons/search/search.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts index b049eba7df..8585889db2 100644 --- a/src/addons/search/search.ts +++ b/src/addons/search/search.ts @@ -8,24 +8,25 @@ declare var exports: any; declare var module: any; declare var define: any; declare var require: any; +declare var window: any; (function (addon) { if ('Terminal' in window) { - /* + /** * Plain browser environment */ - addon((window).Terminal); - } else if (typeof define == 'function') { - /* - * Require.js is available - */ - define(['../../xterm'], addon); + addon(window.Terminal); } else if (typeof exports === 'object' && typeof module === 'object') { - /* + /** * CommonJS environment */ - var xterm = '../../xterm'; // Put in a variable do it's not pulled in by browserify + const xterm = '../../xterm'; module.exports = addon(require(xterm)); + } else if (typeof define == 'function') { + /** + * Require.js is available + */ + define(['../../xterm'], addon); } })((Terminal: any) => { /** From 4b0cf2ffcecf9eac6f607a2b5ce213001f48d497 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 00:36:15 -0700 Subject: [PATCH 15/19] jsdoc --- src/addons/search/search.ts | 4 ++-- src/addons/search/searchHelper.ts | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts index 8585889db2..5a227a8a15 100644 --- a/src/addons/search/search.ts +++ b/src/addons/search/search.ts @@ -32,7 +32,7 @@ declare var window: any; /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term The term to search for. + * @param term Tne search term. * @return Whether a result was found. */ Terminal.prototype.findNext = function(term: string): boolean { @@ -45,7 +45,7 @@ declare var window: any; /** * Find the previous instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term The term to search for. + * @param term Tne search term. * @return Whether a result was found. */ Terminal.prototype.findPrevious = function(term: string): boolean { diff --git a/src/addons/search/searchHelper.ts b/src/addons/search/searchHelper.ts index 6f88e04b91..f28514475a 100644 --- a/src/addons/search/searchHelper.ts +++ b/src/addons/search/searchHelper.ts @@ -11,6 +11,9 @@ interface ISearchResult { row: number; } +/** + * A class that knows how to search the terminal and how to display the results. + */ export class SearchHelper { constructor(private _terminal: any, private _translateBufferLineToString: any) { // TODO: Search for multiple instances on 1 line @@ -22,7 +25,7 @@ export class SearchHelper { /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term The term to search for. + * @param term Tne search term. * @return Whether a result was found. */ public findNext(term: string): boolean { @@ -63,7 +66,7 @@ export class SearchHelper { /** * Find the previous instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term The term to search for. + * @param term Tne search term. * @return Whether a result was found. */ public findPrevious(term: string): boolean { @@ -101,6 +104,12 @@ export class SearchHelper { return this._selectResult(result); } + /** + * Searches a line for a search term. + * @param term Tne search term. + * @param y The line to search. + * @return The search result if it was found. + */ private _findInLine(term: string, y: number): ISearchResult { const bufferLine = this._terminal.lines.get(y); const lowerStringLine = this._translateBufferLineToString(bufferLine, true).toLowerCase(); @@ -115,6 +124,11 @@ export class SearchHelper { } } + /** + * Selects and scrolls to a result. + * @param result The result to select. + * @return Whethera result was selected. + */ private _selectResult(result: ISearchResult): boolean { if (!result) { return false; From 2564592c095da73bad4a305c03f29c00fe1b7c46 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 00:55:50 -0700 Subject: [PATCH 16/19] Change case of search addon files --- src/addons/search/{search.ts => Search.ts} | 0 src/addons/search/{searchHelper.ts => SearchHelper.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/addons/search/{search.ts => Search.ts} (100%) rename src/addons/search/{searchHelper.ts => SearchHelper.ts} (100%) diff --git a/src/addons/search/search.ts b/src/addons/search/Search.ts similarity index 100% rename from src/addons/search/search.ts rename to src/addons/search/Search.ts diff --git a/src/addons/search/searchHelper.ts b/src/addons/search/SearchHelper.ts similarity index 100% rename from src/addons/search/searchHelper.ts rename to src/addons/search/SearchHelper.ts From c13b86a88559663a343e5cb968fbd0563b9c6e15 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 01:03:10 -0700 Subject: [PATCH 17/19] Add find to demo --- demo/index.html | 7 +++++++ demo/main.js | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/demo/index.html b/demo/index.html index 9bba5bd033..ee765c2057 100644 --- a/demo/index.html +++ b/demo/index.html @@ -16,6 +16,13 @@

xterm.js: xterm, in the browser

+
+

Actions

+

+ + +

+

Options

diff --git a/demo/main.js b/demo/main.js index c8d03ae1a1..9098c2f02d 100644 --- a/demo/main.js +++ b/demo/main.js @@ -7,6 +7,10 @@ var term, charHeight; var terminalContainer = document.getElementById('terminal-container'), + actionElements = { + findNext: document.querySelector('#find-next'), + findPrevious: document.querySelector('#find-previous') + }, optionElements = { cursorBlink: document.querySelector('#option-cursor-blink'), cursorStyle: document.querySelector('#option-cursor-style'), @@ -30,6 +34,19 @@ function setTerminalSize () { colsElement.addEventListener('change', setTerminalSize); rowsElement.addEventListener('change', setTerminalSize); +actionElements.findNext.addEventListener('keypress', function (e) { + if (e.key === "Enter") { + e.preventDefault(); + term.findNext(actionElements.findNext.value); + } +}); +actionElements.findPrevious.addEventListener('keypress', function (e) { + if (e.key === "Enter") { + e.preventDefault(); + term.findPrevious(actionElements.findPrevious.value); + } +}); + optionElements.cursorBlink.addEventListener('change', function () { term.setOption('cursorBlink', optionElements.cursorBlink.checked); }); From c62923fb1de4318eb79d76c398053c15fca7734b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 01:09:44 -0700 Subject: [PATCH 18/19] Change case of browserify-addons files --- gulpfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 9b0a6de73f..c9a0f1a0d4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -82,13 +82,13 @@ gulp.task('browserify-addons', ['tsc'], function() { let searchOptions = { basedir: `${buildDir}/addons/search`, debug: true, - entries: [`${outDir}/addons/search/search.js`], + entries: [`${outDir}/addons/search/Search.js`], cache: {}, packageCache: {} }; let searchBundle = browserify(searchOptions) .bundle() - .pipe(source('./addons/search/search.js')) + .pipe(source('./addons/search/Search.js')) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''})) .pipe(sourcemaps.write('./')) From 73970ec5a2b156b37645989d708fd04170db06c1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 9 Jul 2017 01:39:53 -0700 Subject: [PATCH 19/19] Fix casing of search.js --- gulpfile.js | 4 ++-- src/addons/search/{Search.ts => search.ts} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/addons/search/{Search.ts => search.ts} (100%) diff --git a/gulpfile.js b/gulpfile.js index c9a0f1a0d4..9b0a6de73f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -82,13 +82,13 @@ gulp.task('browserify-addons', ['tsc'], function() { let searchOptions = { basedir: `${buildDir}/addons/search`, debug: true, - entries: [`${outDir}/addons/search/Search.js`], + entries: [`${outDir}/addons/search/search.js`], cache: {}, packageCache: {} }; let searchBundle = browserify(searchOptions) .bundle() - .pipe(source('./addons/search/Search.js')) + .pipe(source('./addons/search/search.js')) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''})) .pipe(sourcemaps.write('./')) diff --git a/src/addons/search/Search.ts b/src/addons/search/search.ts similarity index 100% rename from src/addons/search/Search.ts rename to src/addons/search/search.ts