mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user