提交 d0daae36 编写于 作者: P Peng Lyu

re #45690. Find in chunks.

上级 2678fffd
......@@ -15,6 +15,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { ModelRawContentChangedEvent, IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent, IModelTokensChangedEvent, IModelContentChange } from 'vs/editor/common/model/textModelEvents';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { ITextSnapshot } from 'vs/platform/files/common/files';
import { SearchData } from 'vs/editor/common/model/textModelSearch';
/**
* Vertical Lane in the overview ruler of the editor.
......@@ -1100,6 +1101,7 @@ export interface ITextBuffer {
setEOL(newEOL: '\r\n' | '\n'): void;
applyEdits(rawOperations: IIdentifiedSingleEditOperation[], recordTrimAutoWhitespace: boolean): ApplyEditsResult;
findMatchesLineByLine?(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];
}
/**
......
......@@ -9,6 +9,8 @@ import { CharCode } from 'vs/base/common/charCode';
import { Range } from 'vs/editor/common/core/range';
import { ITextSnapshot } from 'vs/platform/files/common/files';
import { leftest, righttest, updateTreeMetadata, rbDelete, fixInsert, NodeColor, SENTINEL, TreeNode } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
import { SearchData, isValidMatch, Searcher, createFindMatch } from 'vs/editor/common/model/textModelSearch';
import { FindMatch } from 'vs/editor/common/model';
// const lfRegex = new RegExp(/\r\n|\r|\n/g);
......@@ -535,6 +537,138 @@ export class PieceTreeBase {
return this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;
}
public findMatchesInNode(node: TreeNode, searcher: Searcher, startLineNumber: number, startCursor: BufferCursor, endCursor: BufferCursor, searchData: SearchData, captureMatches: boolean, limitResultCount: number, resultLen: number, result: FindMatch[]) {
let buffer = this._buffers[node.piece.bufferIndex];
let startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);
let start = this.offsetInBuffer(node.piece.bufferIndex, startCursor);
let end = this.offsetInBuffer(node.piece.bufferIndex, endCursor);
let m: RegExpExecArray;
// Reset regex to search from the beginning
searcher.reset(start);
let ret: BufferCursor = { line: 0, column: 0 };
do {
m = searcher.next(buffer.buffer);
if (m) {
if (m.index >= end) {
return resultLen;
}
this.positionInBuffer(node, m.index - startOffsetInBuffer, ret);
let lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret);
result[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, ret.column + 1, startLineNumber + lineFeedCnt, ret.column + 1 + m[0].length), m, captureMatches);
if (m.index + m[0].length >= end) {
return resultLen;
}
if (resultLen >= limitResultCount) {
return resultLen;
}
}
} while (m);
return resultLen;
}
public findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {
const result: FindMatch[] = [];
let resultLen = 0;
const searcher = new Searcher(searchData.wordSeparators, searchData.regex);
let startPostion = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);
let endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn);
let start = this.positionInBuffer(startPostion.node, startPostion.remainder);
let end = this.positionInBuffer(endPosition.node, endPosition.remainder);
if (startPostion.node === endPosition.node) {
this.findMatchesInNode(startPostion.node, searcher, searchRange.startLineNumber, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
return result;
}
let startLineNumber = searchRange.startLineNumber;
let currentNode = startPostion.node;
while (currentNode !== endPosition.node) {
let lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end);
if (lineBreakCnt >= 1) {
// last line break position
let lineStarts = this._buffers[currentNode.piece.bufferIndex].lineStarts;
let nextLineStartOffset = lineStarts[start.line + lineBreakCnt];
resultLen = this.findMatchesInNode(currentNode, searcher, startLineNumber, start, this.positionInBuffer(currentNode, nextLineStartOffset), searchData, captureMatches, limitResultCount, resultLen, result);
if (resultLen >= limitResultCount) {
return result;
}
startLineNumber += lineBreakCnt;
}
// search for the remaining content
if (startLineNumber === searchRange.endLineNumber) {
const text = this.getLineContent(startLineNumber).substring(0, searchRange.endColumn - 1);
resultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, 0, resultLen, result, captureMatches, limitResultCount);
return result;
}
resultLen = this._findMatchesInLine(searchData, searcher, this.getLineContent(startLineNumber), startLineNumber, 0, resultLen, result, captureMatches, limitResultCount);
if (resultLen >= limitResultCount) {
return result;
}
startLineNumber++;
startPostion = this.nodeAt2(startLineNumber, 1);
currentNode = startPostion.node;
start = this.positionInBuffer(startPostion.node, startPostion.remainder);
}
if (startLineNumber === searchRange.endLineNumber) {
const text = this.getLineContent(startLineNumber).substring(0, searchRange.endColumn - 1);
resultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, 0, resultLen, result, captureMatches, limitResultCount);
return result;
}
resultLen = this.findMatchesInNode(endPosition.node, searcher, startLineNumber, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
return result;
}
private _findMatchesInLine(searchData: SearchData, searcher: Searcher, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {
const wordSeparators = searchData.wordSeparators;
if (!captureMatches && searchData.simpleSearch) {
const searchString = searchData.simpleSearch;
const searchStringLen = searchString.length;
const textLength = text.length;
let lastMatchIndex = -searchStringLen;
while ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {
if (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {
result[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);
if (resultLen >= limitResultCount) {
return resultLen;
}
}
}
return resultLen;
}
let m: RegExpExecArray;
// Reset regex to search from the beginning
searcher.reset(0);
do {
m = searcher.next(text);
if (m) {
result[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);
if (resultLen >= limitResultCount) {
return resultLen;
}
}
} while (m);
return resultLen;
}
// #endregion
// #region Piece Table
......@@ -744,7 +878,7 @@ export class PieceTreeBase {
this.validateCRLFWithPrevNode(newNode);
}
positionInBuffer(node: TreeNode, remainder: number): BufferCursor {
positionInBuffer(node: TreeNode, remainder: number, ret?: BufferCursor): BufferCursor {
let piece = node.piece;
let bufferIndex = node.piece.bufferIndex;
let lineStarts = this._buffers[bufferIndex].lineStarts;
......@@ -780,6 +914,12 @@ export class PieceTreeBase {
}
}
if (ret) {
ret.line = mid;
ret.column = offset - midStart;
return null;
}
return {
line: mid,
column: offset - midStart
......
......@@ -9,8 +9,9 @@ import { Position } from 'vs/editor/common/core/position';
import * as strings from 'vs/base/common/strings';
import { IValidatedEditOperation } from 'vs/editor/common/model/linesTextBuffer/linesTextBuffer';
import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
import { IIdentifiedSingleEditOperation, EndOfLinePreference, ITextBuffer, ApplyEditsResult, IInternalModelContentChange } from 'vs/editor/common/model';
import { IIdentifiedSingleEditOperation, EndOfLinePreference, ITextBuffer, ApplyEditsResult, IInternalModelContentChange, FindMatch } from 'vs/editor/common/model';
import { ITextSnapshot } from 'vs/platform/files/common/files';
import { SearchData } from 'vs/editor/common/model/textModelSearch';
export class PieceTreeTextBuffer implements ITextBuffer {
private _pieceTree: PieceTreeBase;
......@@ -410,6 +411,10 @@ export class PieceTreeTextBuffer implements ITextBuffer {
return contentChanges;
}
findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {
return this._pieceTree.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
}
// #endregion
// #region helper
......
......@@ -30,7 +30,7 @@ import { getWordAtText } from 'vs/editor/common/model/wordHelper';
import { ModelLinesTokens, ModelTokensChangedEventBuilder } from 'vs/editor/common/model/textModelTokens';
import { guessIndentation } from 'vs/editor/common/model/indentationGuesser';
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { TextModelSearch, SearchParams } from 'vs/editor/common/model/textModelSearch';
import { TextModelSearch, SearchParams, SearchData } from 'vs/editor/common/model/textModelSearch';
import { TPromise } from 'vs/base/common/winjs.base';
import { IStringStream, ITextSnapshot } from 'vs/platform/files/common/files';
import { LinesTextBufferBuilder } from 'vs/editor/common/model/linesTextBuffer/linesTextBufferBuilder';
......@@ -983,6 +983,10 @@ export class TextModel extends Disposable implements model.ITextModel {
return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
}
private findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): model.FindMatch[] {
return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
}
public findMatches(searchString: string, rawSearchScope: any, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean, limitResultCount: number = LIMIT_FIND_COUNT): model.FindMatch[] {
this._assertNotDisposed();
......@@ -993,6 +997,18 @@ export class TextModel extends Disposable implements model.ITextModel {
searchRange = this.getFullModelRange();
}
if (!isRegex && searchString.indexOf('\n') < 0 && OPTIONS.TEXT_BUFFER_IMPLEMENTATION === TextBufferType.PieceTree) {
// not regex, not multi line
const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
const searchData = searchParams.parseSearchRequest();
if (!searchData) {
return [];
}
return this.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
}
return TextModelSearch.findMatches(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchRange, captureMatches, limitResultCount);
}
......
......@@ -116,7 +116,7 @@ export class SearchData {
}
}
function createFindMatch(range: Range, rawMatches: RegExpExecArray, captureMatches: boolean): FindMatch {
export function createFindMatch(range: Range, rawMatches: RegExpExecArray, captureMatches: boolean): FindMatch {
if (!captureMatches) {
return new FindMatch(range, null);
}
......@@ -434,6 +434,11 @@ function leftIsWordBounday(wordSeparators: WordCharacterClassifier, text: string
return true;
}
if (charBefore === CharCode.CarriageReturn || charBefore === CharCode.LineFeed) {
// The character before the match is line break or carriage return.
return true;
}
if (matchLength > 0) {
const firstCharInMatch = text.charCodeAt(matchStartIndex);
if (wordSeparators.get(firstCharInMatch) !== WordCharacterClass.Regular) {
......@@ -457,6 +462,11 @@ function rightIsWordBounday(wordSeparators: WordCharacterClassifier, text: strin
return true;
}
if (charAfter === CharCode.CarriageReturn || charAfter === CharCode.LineFeed) {
// The character after the match is line break or carriage return.
return true;
}
if (matchLength > 0) {
const lastCharInMatch = text.charCodeAt(matchStartIndex + matchLength - 1);
if (wordSeparators.get(lastCharInMatch) !== WordCharacterClass.Regular) {
......@@ -468,14 +478,14 @@ function rightIsWordBounday(wordSeparators: WordCharacterClassifier, text: strin
return false;
}
function isValidMatch(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {
export function isValidMatch(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {
return (
leftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)
&& rightIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)
);
}
class Searcher {
export class Searcher {
private _wordSeparators: WordCharacterClassifier;
private _searchRegex: RegExp;
private _prevMatchStartIndex: number;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册