Merge remote-tracking branch 'origin/master' into 1128_addons
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { ISearchHelper, ISearchAddonTerminal, ISearchOptions, ISearchResult } from './Interfaces';
|
||||
import { IDisposable } from 'xterm';
|
||||
|
||||
const NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\;:"\',./<>?';
|
||||
const LINES_CACHE_TIME_TO_LIVE = 15 * 1000; // 15 secs
|
||||
@@ -19,6 +20,8 @@ export class SearchHelper implements ISearchHelper {
|
||||
*/
|
||||
private _linesCache: string[] = null;
|
||||
private _linesCacheTimeoutId = 0;
|
||||
private _cursorMoveListener: IDisposable | undefined;
|
||||
private _resizeListener: IDisposable | undefined;
|
||||
|
||||
constructor(private _terminal: ISearchAddonTerminal) {
|
||||
this._destroyLinesCache = this._destroyLinesCache.bind(this);
|
||||
@@ -55,12 +58,27 @@ export class SearchHelper implements ISearchHelper {
|
||||
|
||||
this._initLinesCache();
|
||||
|
||||
// A row that has isWrapped = false
|
||||
let findingRow = startRow;
|
||||
// index of beginning column that _findInLine need to scan.
|
||||
let cumulativeCols = startCol;
|
||||
// If startRow is wrapped row, scan for unwrapped row above.
|
||||
// So we can start matching on wrapped line from long unwrapped line.
|
||||
while (this._terminal._core.buffer.lines.get(findingRow).isWrapped) {
|
||||
findingRow--;
|
||||
cumulativeCols += this._terminal.cols;
|
||||
}
|
||||
|
||||
// Search startRow
|
||||
result = this._findInLine(term, startRow, startCol, searchOptions);
|
||||
result = this._findInLine(term, findingRow, cumulativeCols, searchOptions);
|
||||
|
||||
// Search from startRow + 1 to end
|
||||
if (!result) {
|
||||
|
||||
for (let y = startRow + 1; y < this._terminal._core.buffer.ybase + this._terminal.rows; y++) {
|
||||
|
||||
// If the current line is wrapped line, increase index of column to ignore the previous scan
|
||||
// Otherwise, reset beginning column index to zero with set new unwrapped line index
|
||||
result = this._findInLine(term, y, 0, searchOptions);
|
||||
if (result) {
|
||||
break;
|
||||
@@ -71,7 +89,7 @@ export class SearchHelper implements ISearchHelper {
|
||||
// Search from the top to the startRow (search the whole startRow again in
|
||||
// case startCol > 0)
|
||||
if (!result) {
|
||||
for (let y = 0; y <= startRow; y++) {
|
||||
for (let y = 0; y < findingRow; y++) {
|
||||
result = this._findInLine(term, y, 0, searchOptions);
|
||||
if (result) {
|
||||
break;
|
||||
@@ -100,8 +118,8 @@ export class SearchHelper implements ISearchHelper {
|
||||
}
|
||||
|
||||
const isReverseSearch = true;
|
||||
let startRow = this._terminal._core.buffer.ydisp;
|
||||
let startCol: number = this._terminal._core.buffer.lines.get(startRow).length;
|
||||
let startRow = this._terminal._core.buffer.ydisp + this._terminal.rows - 1;
|
||||
let startCol = this._terminal.cols;
|
||||
|
||||
if (selectionManager.selectionStart) {
|
||||
// Start from the selection start if there is a selection
|
||||
@@ -118,11 +136,24 @@ export class SearchHelper implements ISearchHelper {
|
||||
|
||||
// Search from startRow - 1 to top
|
||||
if (!result) {
|
||||
// If the line is wrapped line, increase number of columns that is needed to be scanned
|
||||
// Se we can scan on wrapped line from unwrapped line
|
||||
let cumulativeCols = this._terminal.cols;
|
||||
if (this._terminal._core.buffer.lines.get(startRow).isWrapped) {
|
||||
cumulativeCols += startCol;
|
||||
}
|
||||
for (let y = startRow - 1; y >= 0; y--) {
|
||||
result = this._findInLine(term, y, this._terminal._core.buffer.lines.get(y).length, searchOptions, isReverseSearch);
|
||||
result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
// If the current line is wrapped line, increase scanning range,
|
||||
// preparing for scanning on unwrapped line
|
||||
if (this._terminal._core.buffer.lines.get(y).isWrapped) {
|
||||
cumulativeCols += this._terminal.cols;
|
||||
} else {
|
||||
cumulativeCols = this._terminal.cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +161,17 @@ export class SearchHelper implements ISearchHelper {
|
||||
// case startCol > 0)
|
||||
if (!result) {
|
||||
const searchFrom = this._terminal._core.buffer.ybase + this._terminal.rows - 1;
|
||||
let cumulativeCols = this._terminal.cols;
|
||||
for (let y = searchFrom; y >= startRow; y--) {
|
||||
result = this._findInLine(term, y, this._terminal._core.buffer.lines.get(y).length, searchOptions, isReverseSearch);
|
||||
result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
if (this._terminal._core.buffer.lines.get(y).isWrapped) {
|
||||
cumulativeCols += this._terminal.cols;
|
||||
} else {
|
||||
cumulativeCols = this._terminal.cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +185,8 @@ export class SearchHelper implements ISearchHelper {
|
||||
private _initLinesCache(): void {
|
||||
if (!this._linesCache) {
|
||||
this._linesCache = new Array(this._terminal._core.buffer.length);
|
||||
this._terminal.on('cursormove', this._destroyLinesCache);
|
||||
this._cursorMoveListener = this._terminal.onCursorMove(() => this._destroyLinesCache());
|
||||
this._resizeListener = this._terminal.onResize(() => this._destroyLinesCache());
|
||||
}
|
||||
|
||||
window.clearTimeout(this._linesCacheTimeoutId);
|
||||
@@ -157,7 +195,14 @@ export class SearchHelper implements ISearchHelper {
|
||||
|
||||
private _destroyLinesCache(): void {
|
||||
this._linesCache = null;
|
||||
this._terminal.off('cursormove', this._destroyLinesCache);
|
||||
if (this._cursorMoveListener) {
|
||||
this._cursorMoveListener.dispose();
|
||||
this._cursorMoveListener = undefined;
|
||||
}
|
||||
if (this._resizeListener) {
|
||||
this._resizeListener.dispose();
|
||||
this._resizeListener = undefined;
|
||||
}
|
||||
if (this._linesCacheTimeoutId) {
|
||||
window.clearTimeout(this._linesCacheTimeoutId);
|
||||
this._linesCacheTimeoutId = 0;
|
||||
@@ -187,10 +232,11 @@ export class SearchHelper implements ISearchHelper {
|
||||
* @return The search result if it was found.
|
||||
*/
|
||||
protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult {
|
||||
|
||||
// Ignore wrapped lines, only consider on unwrapped line (first row of command string).
|
||||
if (this._terminal._core.buffer.lines.get(row).isWrapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stringLine = this._linesCache ? this._linesCache[row] : void 0;
|
||||
if (stringLine === void 0) {
|
||||
stringLine = this.translateBufferLineToStringWithWrap(row, true);
|
||||
|
||||
@@ -5,11 +5,16 @@
|
||||
* Implements the attach method, that attaches the terminal to a WebSocket stream.
|
||||
*/
|
||||
|
||||
import { Terminal } from 'xterm';
|
||||
import { Terminal, IDisposable } from 'xterm';
|
||||
|
||||
export interface ITerminadoAddonTerminal extends Terminal {
|
||||
_core: {
|
||||
register<T extends IDisposable>(d: T): void;
|
||||
};
|
||||
|
||||
__socket?: WebSocket;
|
||||
__attachSocketBuffer?: string;
|
||||
__dataListener?: IDisposable;
|
||||
|
||||
__getMessage?(ev: MessageEvent): void;
|
||||
__flushBuffer?(): void;
|
||||
|
||||
@@ -59,9 +59,9 @@ export function terminadoAttach(term: Terminal, socket: WebSocket, bidirectional
|
||||
socket.addEventListener('message', addonTerminal.__getMessage);
|
||||
|
||||
if (bidirectional) {
|
||||
addonTerminal.on('data', addonTerminal.__sendData);
|
||||
addonTerminal._core.register(addonTerminal.onData(addonTerminal.__sendData));
|
||||
}
|
||||
addonTerminal.on('resize', addonTerminal.__setSize);
|
||||
addonTerminal._core.register(addonTerminal.onResize(addonTerminal.__setSize));
|
||||
|
||||
socket.addEventListener('close', () => terminadoDetach(addonTerminal, socket));
|
||||
socket.addEventListener('error', () => terminadoDetach(addonTerminal, socket));
|
||||
@@ -75,7 +75,8 @@ export function terminadoAttach(term: Terminal, socket: WebSocket, bidirectional
|
||||
*/
|
||||
export function terminadoDetach(term: Terminal, socket: WebSocket): void {
|
||||
const addonTerminal = <ITerminadoAddonTerminal>term;
|
||||
addonTerminal.off('data', addonTerminal.__sendData);
|
||||
addonTerminal.__dataListener.dispose();
|
||||
addonTerminal.__dataListener = undefined;
|
||||
|
||||
socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user