Very basic find implementation

Part of #553
This commit is contained in:
Daniel Imms
2017-06-12 16:27:13 -07:00
parent a889fef752
commit 8d12881a1c
4 changed files with 90 additions and 0 deletions
+3
View File
@@ -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 {
+75
View File
@@ -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);
}
}
+9
View File
@@ -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.
+3
View File
@@ -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);