Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add search result count to SearchAddon #3716

Merged
merged 32 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b78cb4c
add find count
meganrogge Mar 23, 2022
bb0f5d6
Merge branch 'xtermjs:master' into findCount
meganrogge Mar 28, 2022
c1c0df4
remove index for now
meganrogge Mar 28, 2022
7cc868b
Merge branch 'findCount' of https://github.com/meganrogge/xterm.js in…
meganrogge Mar 28, 2022
6e7d1de
add jsdoc
meganrogge Mar 28, 2022
6ff999b
update jsdoc
meganrogge Mar 28, 2022
463a0e9
property instead of method
meganrogge Mar 29, 2022
49a170f
return undefined when no search results
meganrogge Mar 29, 2022
691f3c9
initialize maps in highlightAllMatches
meganrogge Mar 29, 2022
9a93d5c
! -> ?
meganrogge Mar 29, 2022
d764281
add event to indicate when results have changed
meganrogge Mar 29, 2022
4b6198e
Update addons/xterm-addon-search/src/SearchAddon.ts
meganrogge Mar 29, 2022
f59db29
refactor
meganrogge Mar 29, 2022
dc490d1
Merge branch 'findCount' of https://github.com/meganrogge/xterm.js in…
meganrogge Mar 29, 2022
3df6be8
clear decorations find previous
meganrogge Mar 30, 2022
e2541a1
import
meganrogge Mar 30, 2022
1f00d13
correct ts config
meganrogge Mar 30, 2022
c7d24bf
Update addons/xterm-addon-search/tsconfig.json
meganrogge Mar 30, 2022
f93e166
Update addons/xterm-addon-search/src/SearchAddon.ts
meganrogge Mar 30, 2022
cd0658d
Update addons/xterm-addon-search/src/SearchAddon.ts
meganrogge Mar 30, 2022
f1a75b4
Merge branch 'master' into findCount
meganrogge Mar 30, 2022
56ab94d
refactor to fire event
meganrogge Mar 30, 2022
371f552
Merge branch 'findCount' of https://github.com/meganrogge/xterm.js in…
meganrogge Mar 30, 2022
7099b03
clean up
meganrogge Mar 30, 2022
3995283
revert changes to d.ts
meganrogge Mar 30, 2022
2bce7f4
d.ts
meganrogge Mar 30, 2022
c01aa9e
fix remaining issues
meganrogge Mar 30, 2022
c2df04a
add webpack config change
meganrogge Mar 30, 2022
0c325c8
fix check
meganrogge Mar 30, 2022
2bbcf8c
remove bad conditional
meganrogge Mar 30, 2022
e5fd206
zero based indexing
meganrogge Mar 30, 2022
0ea5e2b
check not undefined
meganrogge Mar 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 56 additions & 17 deletions addons/xterm-addon-search/src/SearchAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { Terminal, IDisposable, ITerminalAddon, ISelectionPosition, IDecoration } from 'xterm';
import { EventEmitter } from 'common/EventEmitter';

export interface ISearchOptions {
regex?: boolean;
Expand Down Expand Up @@ -53,8 +54,8 @@ export class SearchAddon implements ITerminalAddon {
private _dataChanged: boolean = false;
private _cachedSearchTerm: string | undefined;
private _selectedDecoration: IDecoration | undefined;
private _resultDecorations: Map<number, IDecoration[]> = new Map<number, IDecoration[]>();
private _searchResults: Map<string, ISearchResult> = new Map();
private _resultDecorations: Map<number, IDecoration[]> | undefined;
private _searchResults: Map<string, ISearchResult> | undefined;
private _onDataDisposable: IDisposable | undefined;
private _lastSearchOptions: ISearchOptions | undefined;
private _highlightTimeout: number | undefined;
Expand All @@ -68,6 +69,11 @@ export class SearchAddon implements ITerminalAddon {
private _cursorMoveListener: IDisposable | undefined;
private _resizeListener: IDisposable | undefined;

private _resultIndex: number | undefined;

private readonly _onDidChangeResults = new EventEmitter<void>();
public readonly onDidChangeResults = this._onDidChangeResults.event;

public activate(terminal: Terminal): void {
this._terminal = terminal;
this._onDataDisposable = this._terminal.onData(() => {
Expand All @@ -76,7 +82,7 @@ export class SearchAddon implements ITerminalAddon {
window.clearTimeout(this._highlightTimeout);
}
this._highlightTimeout = setTimeout(() => {
if (this._lastSearchOptions?.decorations && this._cachedSearchTerm && this._resultDecorations.size > 0 && this._lastSearchOptions) {
if (this._lastSearchOptions?.decorations && this._cachedSearchTerm && this._resultDecorations?.size && this._resultDecorations.size > 0 && this._lastSearchOptions) {
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
this._highlightAllMatches(this._cachedSearchTerm, this._lastSearchOptions);
}
}, 200);
Expand All @@ -90,14 +96,18 @@ export class SearchAddon implements ITerminalAddon {

public clearDecorations(): void {
this._selectedDecoration?.dispose();
this._terminal?.clearSelection();
this._searchResults.clear();
// this._terminal?.clearSelection();
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
this._searchResults?.clear();
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
this._disposeDecorations();
this._cachedSearchTerm = undefined;
this._dataChanged = true;
this._resultIndex = undefined;
}

private _disposeDecorations(): void {
if (!this._resultDecorations) {
return;
}
this._resultDecorations.forEach(decorations => {
for (const d of decorations) {
d.dispose();
Expand All @@ -113,22 +123,28 @@ export class SearchAddon implements ITerminalAddon {
* @param searchOptions Search options.
* @return Whether a result was found.
*/
public findNext(term: string, searchOptions?: ISearchOptions): boolean {
public findNext(term: string, searchOptions?: ISearchOptions): boolean | { resultIndex: number, resultCount: number } {
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
this._lastSearchOptions = searchOptions;
const findNextResult = this._findNextAndSelect(term, searchOptions);
if (searchOptions?.decorations) {
this._highlightAllMatches(term, searchOptions);
}
return findNextResult;
const findNextResult = this._findNextAndSelect(term, searchOptions);
return this._resultIndex ? { resultIndex: this._resultIndex!, resultCount: this._searchResults?.size || 0 } : findNextResult;
}

private _highlightAllMatches(term: string, searchOptions: ISearchOptions): void {
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
if (!this._searchResults) {
this._searchResults = new Map<string, ISearchResult>();
}
if (!this._resultDecorations) {
this._resultDecorations = new Map<number, IDecoration[]>();
}
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
if (!term || term.length === 0) {
this.clearDecorations();
return;
Expand All @@ -137,8 +153,10 @@ export class SearchAddon implements ITerminalAddon {
if (term === this._cachedSearchTerm && !this._dataChanged) {
return;
}
const dataDrivenChange = term === this._cachedSearchTerm && this._dataChanged;
const lastSearchCount = this._searchResults.size;
// new search, clear out the old decorations
this._disposeDecorations();
this.clearDecorations();
this._searchResults.clear();
let result = this._find(term, 0, 0, searchOptions);
while (result && !this._searchResults.get(`${result.row}-${result.col}`)) {
Expand All @@ -153,9 +171,9 @@ export class SearchAddon implements ITerminalAddon {
this._searchResults.forEach(result => {
const resultDecoration = this._createResultDecoration(result, searchOptions.decorations!);
if (resultDecoration) {
const decorationsForLine = this._resultDecorations.get(resultDecoration.marker.line) || [];
const decorationsForLine = this._resultDecorations!.get(resultDecoration.marker.line) || [];
decorationsForLine.push(resultDecoration);
this._resultDecorations.set(resultDecoration.marker.line, decorationsForLine);
this._resultDecorations!.set(resultDecoration.marker.line, decorationsForLine);
}
});
if (this._dataChanged) {
Expand All @@ -164,6 +182,9 @@ export class SearchAddon implements ITerminalAddon {
if (this._searchResults.size > 0) {
this._cachedSearchTerm = term;
}
if (dataDrivenChange && lastSearchCount !== this._searchResults.size) {
this._onDidChangeResults.fire();
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
}
}

private _find(term: string, startRow: number, startCol: number, searchOptions?: ISearchOptions): ISearchResult | undefined {
Expand Down Expand Up @@ -210,6 +231,16 @@ export class SearchAddon implements ITerminalAddon {
this.clearDecorations();
return false;
}
if (this._searchResults) {
if (!this._resultIndex) {
this._resultIndex = 1;
} else {
this._resultIndex++;
if (this._resultIndex > this._searchResults.size) {
this._resultIndex = 1;
}
}
}

let startCol = 0;
let startRow = 0;
Expand Down Expand Up @@ -264,7 +295,6 @@ export class SearchAddon implements ITerminalAddon {
searchPosition.startCol = 0;
result = this._findInLine(term, searchPosition, searchOptions);
}

// Set selection and scroll if a result was found
return this._selectResult(result, searchOptions?.decorations);
}
Expand All @@ -275,16 +305,16 @@ export class SearchAddon implements ITerminalAddon {
* @param searchOptions Search options.
* @return Whether a result was found.
*/
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean {
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean | { resultIndex: number, resultCount: number } {
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
this._lastSearchOptions = searchOptions;
const findPreviousResult = this._findAndSelectPrevious(term, searchOptions);
if (searchOptions?.decorations) {
this._highlightAllMatches(term, searchOptions);
}
return findPreviousResult;
const findPreviousResult = this._findAndSelectPrevious(term, searchOptions);
return this._resultIndex ? { resultIndex: this._resultIndex, resultCount: this._searchResults?.size || 0 }: findPreviousResult;
}

private _findAndSelectPrevious(term: string, searchOptions?: ISearchOptions): boolean {
Expand All @@ -299,6 +329,16 @@ export class SearchAddon implements ITerminalAddon {
return false;
}

if (this._searchResults) {
if (!this._resultIndex) {
this._resultIndex = this._searchResults?.size;
} else {
this._resultIndex--;
if (this._resultIndex === 0) {
this._resultIndex = this._searchResults?.size;
}
}
}
let startRow = this._terminal.buffer.active.baseY + this._terminal.rows;
let startCol = this._terminal.cols;
const isReverseSearch = true;
Expand Down Expand Up @@ -355,7 +395,6 @@ export class SearchAddon implements ITerminalAddon {
}
}
}

// If there is only one result, return true.
if (!result && currentSelection) return true;

Expand Down Expand Up @@ -669,7 +708,7 @@ export class SearchAddon implements ITerminalAddon {
marker,
x: result.col,
width: result.size,
overviewRulerOptions: this._resultDecorations.get(marker.line) && !this._dataChanged ? undefined : {
overviewRulerOptions: this._resultDecorations?.get(marker.line) && !this._dataChanged ? undefined : {
color: decorations.matchOverviewRuler, position: 'center'
}
});
Expand Down
18 changes: 17 additions & 1 deletion addons/xterm-addon-search/src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,26 @@
"strict": true,
"types": [
"../../../node_modules/@types/mocha"
]
],
"paths": {
"common/*": [
"../../../src/common/*"
],
"browser/*": [
"../../../src/browser/*"
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
]
}
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{
"path": "../../../src/common"
},
{
"path": "../../../src/browser"
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
}
]
}
2 changes: 1 addition & 1 deletion addons/xterm-addon-search/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"include": [],
"references": [
{ "path": "./src" },
{ "path": "./test" }
{ "path": "./test" },
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
]
}
16 changes: 13 additions & 3 deletions addons/xterm-addon-search/typings/xterm-addon-search.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @license MIT
*/

import { Terminal, ILinkMatcherOptions, IDisposable, ITerminalAddon } from 'xterm';
import { Terminal, ITerminalAddon, IEvent } from 'xterm';

declare module 'xterm-addon-search' {
/**
Expand Down Expand Up @@ -95,20 +95,30 @@ declare module 'xterm-addon-search' {
* options.
* @param term The search term.
* @param searchOptions The options for the search.
* @returns the result index and result count if decorations are provided or a boolean
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
* indicating if there was a match
*/
public findNext(term: string, searchOptions?: ISearchOptions): boolean;
public findNext(term: string, searchOptions?: ISearchOptions): boolean | { resultIndex: number, resultCount: number };

/**
* Search backwards for the previous result that matches the search term and
* options.
* @param term The search term.
* @param searchOptions The options for the search.
* @returns the result index and result count if decorations are provided or a boolean
* indicating if there was a match
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
*/
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean;
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean | { resultIndex: number, resultCount: number };

/**
* Clears the decorations and selection
*/
public clearDecorations(): void;

/**
* An event listener for when the search results change
* as a result of the buffer changing
*/
onDidChangeResults: IEvent<void>;
}
}